如何以编程方式在Android 4.1中接听/结束通话?

我正在写一个Android应用程序,我需要接听来电,做一些工作,然后结束通话。 所有的谷歌search后,我可以find两种不同的方式来实现这两个不适用于最新版本的Android,特别是4.1之后,果冻豆。

I.)在“android.intent.action.PHONE_STATE”广播接收器中使用Javareflection访问“com.android.internal.telephony.ITelephony”。 下面的示例代码可以在数百个相关的post中find:

public class PhoneCallReceiver extends BroadcastReceiver { Context context = null; private static final String TAG = "Phone call"; private ITelephony telephonyService; @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) return; Log.v(TAG, "Receving...."); TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try { Log.v(TAG, "Get getTeleService..."); Class c = Class.forName(telephony.getClass().getName()); Method m = c.getDeclaredMethod("getITelephony"); m.setAccessible(true); telephonyService = (ITelephony) m.invoke(telephony); telephonyService.silenceRinger(); Log.v(TAG, "Answering Call now..."); telephonyService.answerRingingCall(); Log.v(TAG, "Call answered..."); //telephonyService.endCall(); } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "FATAL ERROR: could not connect to telephony subsystem"); Log.e(TAG, "Exception object: " + e); } } } 

这个代码的问题是

 <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> 

是此方法工作所必需的,并且此权限已被定义为“仅用于系统应用程序”,来自android v 2.3。 简而言之,普通用户应用程序无法再在清单文件中定义此权限。

另一种方法是模拟推动耳机挂钩,使Android应答呼叫。 这通过广播“Intent.ACTION_MEDIA_BUTTON”来完成,如下面的代码所示。

 public class PhoneCallReceiver extends BroadcastReceiver { Context context = null; private static final String TAG = "Phone call"; @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) return; String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); Intent answer = new Intent(Intent.ACTION_MEDIA_BUTTON); answer.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); context.sendOrderedBroadcast(answer, null); Log.d(TAG, "Answered incoming call from: " + number); } return; } } 

此方法工作,直到Android 4.1之后,android已经限制用户应用程序广播“Intent.ACTION_MEDIA_BUTTON”。

所以我的结论是,目前没有办法在Android 4.1或更高版本中实现这一点。

有没有其他人发现任何其他的解决scheme或解决这个问题?

这工作从Android 2.2到4.0,现在jointry catch到最后一行它为4.1.2和4.2工作。坦率地说,不知道它是如何工作的,但它适用于我。

  Log.d(tag, "InSecond Method Ans Call"); // 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)); sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED"); 
  Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG); headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); headSetUnPluggedintent.putExtra("state", 0); headSetUnPluggedintent.putExtra("name", "Headset"); try { sendOrderedBroadcast(headSetUnPluggedintent, null); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } 

这对我在Android 4.1.2以及我已经在4.2testing,这仍然给出了一个exception处理。

/ *编辑结束呼叫* /

希望这有助于所有的人寻找全面解决scheme来回答和结束呼叫。

 /** * Reject button click listener will reject the incoming call. */ private class RejectCallOnClickListener implements OnClickListener { @Override public void onClick(View v) { Log.d(tag, "OnRejectButton: " + "Reject OnClick"); ignoreCall(); exitCleanly(); } } /** * ignore incoming calls */ private void ignoreCall() { if (USE_ITELEPHONY) ignoreCallAidl(); else ignoreCallPackageRestart(); } /** * AIDL/ITelephony technique for ignoring calls */ private void ignoreCallAidl() { try { // telephonyService.silenceRinger(); telephonyService.endCall(); } catch (RemoteException e) { e.printStackTrace(); Log.d(tag, "ignoreCall: " + "Error: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); Log.d(tag, "ignoreCall" + "Error: " + e.getMessage()); } } /** * package restart technique for ignoring calls */ private void ignoreCallPackageRestart() { ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); am.restartPackage("com.android.providers.telephony"); am.restartPackage("com.android.phone"); } /** * cleanup and exit routine */ private void exitCleanly() { unHookReceiver(); this.finish(); } 

作为这个线程的结论,这里是适用于Android 4.2.2的代码。

– >通过模拟推耳机挂钩,并保持广播在@PravinDodia在abouve线程中的try-catch。 (注意抛出一个exception并在catch中处理,无论如何call都是可以的,所以我想我们可以忽略这个exception,继续生活,就好像什么都没有发生一样!)

– >使用ITelephony断开呼叫。

 public class PhoneCallReceiver extends BroadcastReceiver { Context context = null; private static final String TAG = "Phone call"; @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) return; else { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { answerPhoneHeadsethook(context, intent); return; } else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){ Log.d(TAG, "CALL ANSWERED NOW!!"); try { synchronized(this) { Log.d(TAG, "Waiting for 10 sec "); this.wait(10000); } } catch(Exception e) { Log.d(TAG, "Exception while waiting !!"); e.printStackTrace(); } disconnectPhoneItelephony(context); return; } else { Log.d(TAG, "ALL DONE ...... !!"); } } } public void answerPhoneHeadsethook(Context context, Intent intent) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.d(TAG, "Incoming call from: " + number); Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON); buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); try { context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED"); Log.d(TAG, "ACTION_MEDIA_BUTTON broadcasted..."); } catch (Exception e) { Log.d(TAG, "Catch block of ACTION_MEDIA_BUTTON broadcast !"); } Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG); headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); headSetUnPluggedintent.putExtra("state", 1); // 0 = unplugged 1 = Headset with microphone 2 = Headset without microphone headSetUnPluggedintent.putExtra("name", "Headset"); // TODO: Should we require a permission? try { context.sendOrderedBroadcast(headSetUnPluggedintent, null); Log.d(TAG, "ACTION_HEADSET_PLUG broadcasted ..."); } catch (Exception e) { // TODO Auto-generated catch block //e.printStackTrace(); Log.d(TAG, "Catch block of ACTION_HEADSET_PLUG broadcast"); Log.d(TAG, "Call Answered From Catch Block !!"); } Log.d(TAG, "Answered incoming call from: " + number); } Log.d(TAG, "Call Answered using headsethook"); } public static void disconnectPhoneItelephony(Context context) { ITelephony telephonyService; Log.v(TAG, "Now disconnecting using ITelephony...."); TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try { Log.v(TAG, "Get getTeleService..."); Class c = Class.forName(telephony.getClass().getName()); Method m = c.getDeclaredMethod("getITelephony"); m.setAccessible(true); telephonyService = (ITelephony) m.invoke(telephony); //telephonyService.silenceRinger(); Log.v(TAG, "Disconnecting Call now..."); //telephonyService.answerRingingCall(); //telephonyService.endcall(); Log.v(TAG, "Call disconnected..."); telephonyService.endCall(); } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "FATAL ERROR: could not connect to telephony subsystem"); Log.e(TAG, "Exception object: " + e); } } } 

至less断开function起作用,我们知道它是如何工作的。 所以那些想要开发Call Barring应用程序的人可以继续。 对于那些想要接听电话的人,我想我们现在可以使用它,只希望它能在下一个版本中停止工作。

尝试这个答案用语法结束通话。 它为我工作很好。

 try { String serviceManagerName = "android.os.ServiceManager"; String serviceManagerNativeName = "android.os.ServiceManagerNative"; String telephonyName = "com.android.internal.telephony.ITelephony"; Class telephonyClass; Class telephonyStubClass; Class serviceManagerClass; Class serviceManagerStubClass; Class serviceManagerNativeClass; Class serviceManagerNativeStubClass; Method telephonyCall; Method telephonyEndCall; Method telephonyAnswerCall; Method getDefault; Method[] temps; Constructor[] serviceManagerConstructor; // Method getService; Object telephonyObject; Object serviceManagerObject; telephonyClass = Class.forName(telephonyName); telephonyStubClass = telephonyClass.getClasses()[0]; serviceManagerClass = Class.forName(serviceManagerName); serviceManagerNativeClass = Class.forName(serviceManagerNativeName); Method getService = // getDefaults[29]; serviceManagerClass.getMethod("getService", String.class); Method tempInterfaceMethod = serviceManagerNativeClass.getMethod( "asInterface", IBinder.class); Binder tmpBinder = new Binder(); tmpBinder.attachInterface(null, "fake"); serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder); IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone"); Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class); telephonyObject = serviceMethod.invoke(null, retbinder); //telephonyCall = telephonyClass.getMethod("call", String.class); telephonyEndCall = telephonyClass.getMethod("endCall"); //telephonyAnswerCall = telephonyClass.getMethod("answerRingingCall"); telephonyEndCall.invoke(telephonyObject); } catch (Exception e) { e.printStackTrace(); Log.error(DialerActivity.this, "FATAL ERROR: could not connect to telephony subsystem"); Log.error(DialerActivity.this, "Exception object: " + e); } 

我的应用程序已经使用下面的代码来回答手机约6个月:

 Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON); i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); context.sendOrderedBroadcast(i, null); 

我已经testing了从2.2到4.2.2的Android版本。 我在我的testingna 4.2.2设备中没有看到SecurityException广播“Intent.ACTION_MEDIA_BUTTON”,也没有看到Play商店的崩溃报告,指出发生了这种exception。

我会说,这并不总是工作。 它不适用于HTC设备,因为HTC设备有一个HeadsetObeserver,可以监听有线耳机的实际插入情况。 如果没有这个事件,它现在是一个第三方应用程序的SecurityException广播,HeadsetHook KeyEvent将被忽略。

以前的答案是误导。 下面的代码块什么也不做:

 Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG); headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); headSetUnPluggedintent.putExtra("state", 0); headSetUnPluggedintent.putExtra("name", "Headset"); try { sendOrderedBroadcast(headSetUnPluggedintent, null); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } 

除了生成一个SecurityException并捕获它。

在代码工作的其他答案中,这是因为广播了KeyEvent.KEYCODE_HEADSETHOOK。

尝试这个 :

 Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON); buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); context.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)); context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED"); 

AndroidManifest.xml文件中添加权限

 <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/> 

ITelephony方法在4.4上不起作用,我发现耳机/媒体button方法在挂断之前仍然允许相当长的响铃。

这个chaps博客文章显示了一个新的方法,我已经testing了4.4.2 Galaxy s4和HTC一个迷你挂起更快,你也没有得到未接来电input。

http://aprogrammersday.blogspot.co.uk/2014/05/disconnect-block-drop-calls-android-4.html

该技术使用下面的运行时执行,显然你可能需要为某些设备使用不同的编号。

 public class HangupPhoneCallReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (TelephonyManager.EXTRA_STATE_RINGING.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) { Executor eS = Executors.newSingleThreadExecutor(); eS.execute(new Runnable() { @Override public void run() { Runtime runtime = Runtime.getRuntime(); try { Log.d(TAG, "service call phone 5 \n"); runtime.exec("service call phone 5 \n"); } catch (Exception exc) { Log.e(TAG, exc.getMessage()); } } }); return; } } } 

使用IT电话断开呼叫在某些设备(如Samsung S Duos)上不起作用。 但你仍然可以让铃声沉默:)