Я пытаюсь реализовать пользовательский экран входящих вызовов/исходящих вызовов. Вот что я пробовал. U дал две проблемы
-
Иногда он вызывает экран ввода по умолчанию на моем телефоне, или иногда он вызывает настраиваемый экран. Я бы всегда звонил по настроенному экрану.
-
Я не могу инициировать вызовы для исходящих. настраиваемый экран просто появляется, но не вызывает никаких вызовов.
Как решить эту проблему, я не уверен, что здесь не так. Было бы здорово, если кто-то может помочь мне исправить это.
Вот что я пытаюсь:
манифеста:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar" >
<activity
android:name="com.honey.ringer.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.honey.ringer.AcceptCall"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.ANSWER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver
android:name="com.honey.ringer.PhoneListenerBroad">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
BroadCastReciever: у него есть как входящие, так и исходящие
public class PhoneListenerBroad extends BroadcastReceiver
{
Context c;
private String outgoing;
@Override
public void onReceive(Context context, Intent intent)
{
c = context;
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
{
outgoing = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
int state = 2;
Intent intentPhoneCall = new Intent(c, AcceptCall.class);
intentPhoneCall.putExtra("incomingnumber", outgoing);
intentPhoneCall.putExtra("state", state);
intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(intentPhoneCall);
}
try
{
TelephonyManager tmgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
catch (Exception e)
{
Log.e("Phone Receive Error", " " + e);
}
}
private class MyPhoneStateListener extends PhoneStateListener
{
public void onCallStateChanged(final int state, final String incomingNumber)
{
Handler callActionHandler = new Handler();
Runnable runRingingActivity = new Runnable()
{
@Override
public void run()
{
if (state == 1)
{
Intent intentPhoneCall = new Intent(c, AcceptCall.class);
intentPhoneCall.putExtra("incomingnumber", incomingNumber);
intentPhoneCall.putExtra("state", state);
intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(intentPhoneCall);
}
}
};
if (state == 1)
{
callActionHandler.postDelayed(runRingingActivity, 100);
}
if (state == 0)
{
callActionHandler.removeCallbacks(runRingingActivity);
}
}
}
}
AcceptCall.java(для целей пользовательского интерфейса - входящие и исходящие):
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class AcceptCall extends Activity implements OnClickListener
{
LinearLayout answerButton;
LinearLayout rejectButton;
LinearLayout timerLayout;
TextView contactName;
TextView contactNumber;
ImageView profile;
private String incomingnumber;
private int state;
String name = null;
String contactId = null;
InputStream photo_stream;
TextView callType;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.testactivity);
answerButton = (LinearLayout) findViewById(R.id.callReceive);
answerButton.setOnClickListener(this);
rejectButton = (LinearLayout) findViewById(R.id.callReject);
rejectButton.setOnClickListener(this);
timerLayout = (LinearLayout) findViewById(R.id.timerLayout);
contactName = (TextView) findViewById(R.id.contactName);
contactNumber = (TextView) findViewById(R.id.contactNumber);
callType = (TextView) findViewById(R.id.callType);
timerValue = (TextView) findViewById(R.id.timerValue);
profile = (ImageView)findViewById(R.id.contactPhoto);
Bundle bundle = getIntent().getExtras();
if(bundle != null)
{
incomingnumber = bundle.getString("incomingnumber");
state = bundle.getInt("state");
}
contactslookup(incomingnumber);
contactName.setText(name);
contactNumber.setText(incomingnumber);
if (state == 2)
{
/*String uri = "tel:" + incomingnumber.trim();
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse(uri));
startActivity(intent);*/
}
PhoneStateListener phoneStateListener = new PhoneStateListener()
{
@Override
public void onCallStateChanged(int state, String incomingNumber)
{
//wen ringing
if (state == TelephonyManager.CALL_STATE_RINGING)
{
Log.e("CALL_STATE_RINGING","CALL_STATE_RINGING");
}
//after call cut
else if(state == TelephonyManager.CALL_STATE_IDLE)
{
RejectCall();
}
//wen speaking / outgoing call
else if(state == TelephonyManager.CALL_STATE_OFFHOOK)
{
Log.e("CALL_STATE_OFFHOOK","CALL_STATE_OFFHOOK");
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if(mgr != null)
{
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
private void contactslookup(String number)
{
Log.v("ffnet", "Started uploadcontactphoto...");
//InputStream input = null;
// define the columns I want the query to return
String[] projection = new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME,ContactsContract.PhoneLookup._ID};
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// query time
Cursor cursor = getContentResolver().query(contactUri, projection, null, null, null);
if (cursor.moveToFirst())
{
// Get values from contacts database:
contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
name = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
else
{
return; // contact not found
}
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= 14)
{
Uri my_contact_Uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), my_contact_Uri, true);
}
else
{
Uri my_contact_Uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), my_contact_Uri);
}
if(photo_stream != null)
{
BufferedInputStream buf =new BufferedInputStream(photo_stream);
Bitmap my_btmp = BitmapFactory.decodeStream(buf);
profile.setImageBitmap(my_btmp);
}
else
{
profile.setImageResource(R.drawable.contactpic);
}
cursor.close();
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
if(v.getId() == answerButton.getId())
{
timerLayout.setVisibility(0);
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
callType.clearAnimation();
// Simulate a press of the headset button to pick up the call
Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
this.sendOrderedBroadcast(buttonDown, "android.permission.CALL_PRIVILEGED");
// froyo and beyond trigger on buttonUp instead of buttonDown
Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
this.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
}
if(v.getId() == rejectButton.getId())
{
RejectCall();
}
}
private void RejectCall()
{
TelephonyManager telephony = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
try {
// Java reflection to gain access to TelephonyManager's
// ITelephony getter
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(telephony);
telephonyService.endCall();
finish();
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
}
catch (Exception e)
{
e.printStackTrace();
Log.e("Error", "FATAL ERROR: could not connect to telephony subsystem");
Log.e("Error", "Exception object: " + e);
}
}
private Runnable updateTimerThread = new Runnable()
{
public void run()
{
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
int mins = secs / 60;
int hours = mins / 60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
timerValue.setText(""+ hours + ":" + String.format("%02d", mins) + ":"
+ String.format("%02d", secs));
customHandler.postDelayed(this, 0);
}
};
}