How to programmatically answer / end a call in Android 4.1?

I am writing an Android application in which I need to answer an incoming call, do some work, and then end the call. After all Googling, I could find two different ways to achieve this, both of which do not work with the latest versions of Android, especially after 4.1, Jelly Bean.

I.) Access to "com.android.internal.telephony.ITelephony" using Java Reflection in the Broadcast receiver for "android.intent.action.PHONE_STATE". Below code example can be found in hundreds of related posts:

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); } } } 

The problem with this code is that

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

this method is required to work, and this permission has been defined as "only for system applications" from android v 2.3. In short, regular user applications can no longer define this permission in the manifest file.

II.) Another way is to simulate a click on the hook of the headset, which causes Android to answer the call. This is done by broadcasting "Intent.ACTION_MEDIA_BUTTON" as shown below.

 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; } } 

This method works before Android 4.1, after which the android restricted user applications from broadcasting "Intent.ACTION_MEDIA_BUTTON".

So, I came to the conclusion that at the moment we can not achieve this in Android 4.1 or later.

Has anyone else found any other solution or workaround for this problem?

+53
android telephony
Mar 18 '13 at 16:11
source share
8 answers

This works from Android 2.2 to 4.0, and now, after adding try try to the last line, it works for 4.1.2 and 4.2. Honestly, I don’t know how it works, but it works for me.

 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) { e.printStackTrace(); } 

This works for me in Android 4.1.2, and I also tested on 4.2. It still gives an exception that is being handled.

Edit to end a call

Hope this helps all people who are looking for a complete solution to answer and end a call.

 /** * 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(); } 
+16
Apr 25 '13 at 18:23
source share

My application used the following code to answer the phone for 6 months:

 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); 

I tested this on Android versions 2.2 to 4.2.2. I did not see the SecurityException translation "Intent.ACTION_MEDIA_BUTTON" in my testing of the n 4.2.2 device, and I did not see crash reports from the Play Store indicating such exceptions.

I will say that this does not always work. It doesn’t work on HTC devices because HTC devices have HeadsetObeserver that listen on the actual connection of the wired headset. Without this event, which is currently a SecurityException exception for a third-party broadcast application, the HeadsetHook KeyEvent is ignored.

The previous answers are misleading. The following code block does nothing:

 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(); } 

with the exception of the generation of a security exception and its capture.

In other answers where the code works, this is because KeyEvent.KEYCODE_HEADSETHOOK is passed.

+8
Jul 08 '13 at 15:16
source share

As a conclusion to this topic, here is the code that works for me for Android 4.2.2.

-> The call is answered by simulating a click on the headset hook and saving the broadcast in try-catch, as mentioned in @PravinDodia in the abouve thread. (Note that the exception is thrown and handled in catch, and the call will be answered anyway. Therefore, I think we can just ignore this exception and continue life as if nothing had happened!)

-> Call disconnected using 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); } } } 

At least the disconnect function works, and we know how it works. Therefore, those who want to develop a call barring application can continue to work. For people like me who want to answer the call, I think we can use it now, and only hope that it does not stop working in the next version.

+7
Jul 05 '13 at 12:03
source share

Try Answer to end the call using the program. His work is wonderful for me.

 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); } 
+7
Nov 28 '13 at 13:44
source share

Try the following:

 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"); 

Add permissions to AndroidManifest.xml as

 <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/> 
+3
Nov 25 '13 at 10:25
source share

The ITelephony method does not work on 4.4, and I find that the headset / media stream button method still allows a rather long ring before hanging.

This blog blog heading shows a new method that I tested as working on 4.4.2 Galaxy s4 and HTC one mini, which hangs much faster and you also don't get a missed call record.

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

The method uses the exec executable, as shown below, maybe for some devices you might need a different number.

 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; } } } 
+3
Sep 17 '14 at 11:22
source share

Disabling a call using IT telephony does not work on some devices, such as Samsung S Duos. But you can still make the call silent :)

+2
01 Oct '13 at 5:27
source share
 To end call in older version then 9.0 use this: TelephonyManager tm = (TelephonyManager)context.getSystemService(TELEPHONY_SERVICE); Method m1 = null; try { m1 = tm.getClass().getDeclaredMethod("getITelephony"); } catch (NoSuchMethodException e) { e.printStackTrace(); } m1.setAccessible(true); Object iTelephony = null; try { iTelephony = m1.invoke(tm); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } Method m3 = null; try { m3 = iTelephony.getClass().getDeclaredMethod("endCall"); } catch (NoSuchMethodException e) { e.printStackTrace(); } try { m3.invoke(iTelephony); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } & for pie TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); if (telecomManager != null) { return telecomManager.endCall(); } Make sure your compile SDK version is 28 
0
Feb 01 '19 at 6:51
source share



All Articles