How to program incoming calls in Android 5.0 (Lollipop)?

As I try to create my own screen for incoming calls, I try to program an answer to an incoming call. I use the following code, but it does not work in Android 5.0.

// 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)); 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"); 
+67
android android-5.0-lollipop phone-call incoming-call
Nov 14 '14 at 6:59
source share
10 answers

Update for Android O

Although the question was originally asked to support Android L, people still seem to be confronted with this question and answer, so the latest improvements in Android O are worth mentioning. Backward compatibility methods are still described below.

What changed?

Starting with Android O , the PHONE permission group also contains the ANSWER_PHONE_CALLS permission . As the name of the permission implies, using it allows your application to programmatically accept incoming calls through a proper API call without any hacking into the system using reflection or imitation of the user.

How do we use this change?

You should check the version of the system at run time if you support older versions of Android so that you can encapsulate this new API call while supporting support for those older versions of Android. You must follow to request permissions at runtime to get this new permission at runtime, as is standard for new versions of Android.

After getting permission, your application simply needs to just call the TelecomManager acceptRingingCall method. The main call is as follows:

 TelecomManager tm = (TelecomManager) mContext .getSystemService(Context.TELECOM_SERVICE); if (tm == null) { // whether you want to handle this is up to you really throw new NullPointerException("tm == null"); } tm.acceptRingingCall();` 



Method 1: TelephonyManager.answerRingingCall ()

If you have unlimited control over your device.

What is it?

There is TelephonyManager.answerRingingCall (), which is a hidden internal method. It works like a bridge for ITelephony.answerRingingCall (), which was discussed on interwebs sites and seems promising from the start. This is not available on 4.4.2_r1 because it was only introduced in commit 83da75d for Android 4.4 KitKat ( line 1537 on 4.4.3_r1 ) and then "reactroduced" in commit f1e1e77 for Lollipop ( line 3138 on 5.0.0_r1 ) because of that how the git tree was structured. This means that if you do not only support devices with Lollipop, which is probably a poor solution based on a tiny market share at the moment, you still need to provide backup methods if you go along this route.

How will we use this?

Since this method is hidden from using SDK applications, you need to use reflection to dynamically learn and use the method at runtime. If you are not familiar with reflection, you can quickly read What is reflection and why is it useful? . You can also delve deeper into the Trail: Reflection API specification if you are interested in this.

And what does it look like in code?

 // set the logging tag constant; you probably want to change this final String LOG_TAG = "TelephonyAnswer"; TelephonyManager tm = (TelephonyManager) mContext .getSystemService(Context.TELEPHONY_SERVICE); try { if (tm == null) { // this will be easier for debugging later on throw new NullPointerException("tm == null"); } // do reflection magic tm.getClass().getMethod("answerRingingCall").invoke(tm); } catch (Exception e) { // we catch it all as the following things could happen: // NoSuchMethodException, if the answerRingingCall() is missing // SecurityException, if the security manager is not happy // IllegalAccessException, if the method is not accessible // IllegalArgumentException, if the method expected other arguments // InvocationTargetException, if the method threw itself // NullPointerException, if something was a null value along the way // ExceptionInInitializerError, if initialization failed // something more crazy, if anything else breaks // TODO decide how to handle this state // you probably want to set some failure state/go to fallback Log.e(LOG_TAG, "Unable to use the Telephony Manager directly.", e); } 

This is too good to be true!

Actually, there is one small problem. This method should be fully functional, but the security manager wants callers to contain android.permission.MODIFY_PHONE_STATE . This permission applies only to the partially documented functions of the system, as third parties should not touch it (as you can see from the documentation for it). You can try adding <uses-permission> , but it will not be useful, because the level of protection for this permission is the signature | system ( see line 1201 of the kernel / AndroidManifest at 5.0.0_r1 ).

You can read Problem 34785: update the documentation on android: protectionLevel , which was created in 2012, to see that we lack information on specific "pipe syntax", but, experimenting around, it seems that it should function as an "AND" , that is, all specified flags must be executed for permission. Working in accordance with this assumption, this means that you must have your application:

  • Installed as a system application.

    This should be good and can be achieved by asking users to install using ZIP in recovery, for example, by rooting or installing Google applications on custom ROMs that no longer have them.

  • A signature with the same signature as frameworks / base aka the system, as well as ROM.

    This is where the problems arise. To do this, you need to use the keys used to sign the framework / database. You will not only need to access Google keys for Nexus factory images, but you will also need to access all the keys of developers from other OEMs and ROMs. This does not seem plausible, so you can subscribe to system keys using a custom ROM and ask your users to switch to it (which can be difficult) or find an exploit that can bypass the protection level (which can also be difficult).

In addition, this behavior seems to be related to Problem 34792: Android Jelly Bean / 4.1: android.permission.READ_LOGS no longer works , which uses the same level of protection along with the undocumented development flag.

Working with TelephonyManager sounds good, but will not work if you do not get the appropriate permission, which is not so easy to do in practice.

How about using TelephonyManager in other ways?

Unfortunately, it seems you need to hold on to android.permission.MODIFY_PHONE_STATE to use cool tools, which in turn means that you go to access these methods with difficulty.




Method 2: service call SERVICE CODE

If you can check whether the work performed on the device will work with the specified code.

Without the ability to interact with TelephonyManager, there is also the possibility of interacting with the service through the service executable.

How it works?

It's pretty simple, but there is even less documentation on this route than others. We know for sure that the executable takes two arguments - the name of the service and the code.

  • the name of the service we want to use is the phone.

    This can be seen by running the service list .

  • the code we want to use was apparently 6, but now it is 5.

    It looks like it was based on IBinder.FIRST_CALL_TRANSACTION + 5 for many versions now (from 1.5_r4 to 4.4.4_r1 ), but during local testing, code 5 worked to answer an incoming call. Since Lollipo is a massive update around the world, the intrinsic elements are also changing.

This is the result of the service call phone 5 command.

How do we use this programmatically?

Java

The following code is a crude implementation designed to function as a proof of concept. If you really want to go further and use this method, you will probably want to check out recommendations on how to use su smoothly and perhaps switch to a more complete libsuperuser Chainfire .

 try { Process proc = Runtime.getRuntime().exec("su"); DataOutputStream os = new DataOutputStream(proc.getOutputStream()); os.writeBytes("service call phone 5\n"); os.flush(); os.writeBytes("exit\n"); os.flush(); if (proc.waitFor() == 255) { // TODO handle being declined root access // 255 is the standard code for being declined root for SU } } catch (IOException e) { // TODO handle I/O going wrong // this probably means that the device isn't rooted } catch (InterruptedException e) { // don't swallow interruptions Thread.currentThread().interrupt(); } 

manifest

 <!-- Inform the user we want them root accesses. --> <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/> 

Does it really require root access?

Unfortunately it is so. You can try using Runtime.exec , but I could not get luck with this route.

How stable is it?

I'm glad you asked. Due to the fact that the documentation is not documented, this can violate different versions, as evidenced by the above code difference. The service name should probably remain on the phone in different assemblies, but as far as we know, the code value can change on several lines of the same version (internal modifications, for example, using the OEM shell), which in turn violates the method used . Therefore, it is worth mentioning that testing was conducted on the Nexus 4 (mako / occam). I personally advise you not to use this method, but since I cannot find a more stable method, I think this is the best shot.




Original Method: Intent of Headset Key Encoding

In those days when you have to be content.

The next section was greatly influenced by this Riley C answer .

The simulated headset wash method published in the original question seems to translate as you would expect, but it doesn't seem to reach the goal of answering the call. Despite the fact that there seems to be code that should handle these intentions, they simply are not interested, which should mean that there should be some new countermeasures for this method. The magazine also does not show anything interesting, and I personally do not think that you need to dig through the Android source, because it will be useful only because Google can make a small change that will easily violate the method used.

Is there anything we can do right now?

The behavior can be sequentially reproduced using an executable input file. It takes a keycode argument, for which we simply pass KeyEvent.KEYCODE_HEADSETHOOK . This method does not even require root access, which makes it suitable for common cases for the general public, but there is a slight flaw in the method - the headset button press event that requires permission cannot be specified, that is, it works like a real button press and bubbles up the whole chain, which, in turn, means that you should be careful when simulating a button press, since this can lead, for example, to starting a music player if none of the higher priority is ready to handle the event s.

The code?

 new Thread(new Runnable() { @Override public void run() { try { Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); } catch (IOException e) { // Runtime.exec(String) had an I/O problem, try to fall back String enforcedPerm = "android.permission.CALL_PRIVILEGED"; Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); mContext.sendOrderedBroadcast(btnDown, enforcedPerm); mContext.sendOrderedBroadcast(btnUp, enforcedPerm); } } }).start(); 



tl; dr, before Android O

  • There is no public API.
  • Internal APIs are disabled or simply without documentation.
  • You must be careful.
+101
Nov 23
source share

A fully working solution is based on @Valter Strods code.

To make it work, you must display the (invisible) activity on the lock screen where the code is executed.

AndroidManifest.xml

 <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <activity android:name="com.mysms.android.lib.activity.AcceptCallActivity" android:launchMode="singleTop" android:excludeFromRecents="true" android:taskAffinity="" android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@style/Mysms.Invisible"> </activity> 

Call Pickup Actions

 package com.mysms.android.lib.activity; import android.app.Activity; import android.app.KeyguardManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.WindowManager; import org.apache.log4j.Logger; import java.io.IOException; public class AcceptCallActivity extends Activity { private static Logger logger = Logger.getLogger(AcceptCallActivity.class); private static final String MANUFACTURER_HTC = "HTC"; private KeyguardManager keyguardManager; private AudioManager audioManager; private CallStateReceiver callStateReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); } @Override protected void onResume() { super.onResume(); registerCallStateReceiver(); updateWindowFlags(); acceptCall(); } @Override protected void onPause() { super.onPause(); if (callStateReceiver != null) { unregisterReceiver(callStateReceiver); callStateReceiver = null; } } private void registerCallStateReceiver() { callStateReceiver = new CallStateReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); registerReceiver(callStateReceiver, intentFilter); } private void updateWindowFlags() { if (keyguardManager.inKeyguardRestrictedInputMode()) { getWindow().addFlags( WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); } else { getWindow().clearFlags( WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); } } private void acceptCall() { // for HTC devices we need to broadcast a connected headset boolean broadcastConnected = MANUFACTURER_HTC.equalsIgnoreCase(Build.MANUFACTURER) && !audioManager.isWiredHeadsetOn(); if (broadcastConnected) { broadcastHeadsetConnected(false); } try { try { logger.debug("execute input keycode headset hook"); Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); } catch (IOException e) { // Runtime.exec(String) had an I/O problem, try to fall back logger.debug("send keycode headset hook intents"); String enforcedPerm = "android.permission.CALL_PRIVILEGED"; Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); sendOrderedBroadcast(btnDown, enforcedPerm); sendOrderedBroadcast(btnUp, enforcedPerm); } } finally { if (broadcastConnected) { broadcastHeadsetConnected(false); } } } private void broadcastHeadsetConnected(boolean connected) { Intent i = new Intent(Intent.ACTION_HEADSET_PLUG); i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); i.putExtra("state", connected ? 1 : 0); i.putExtra("name", "mysms"); try { sendOrderedBroadcast(i, null); } catch (Exception e) { } } private class CallStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { finish(); } } } 

Style

 <style name="Mysms.Invisible"> <item name="android:windowFrame">@null</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle">@null</item> </style> 

Finally, name the magic!

 Intent intent = new Intent(context, AcceptCallActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(intent); 
+32
Apr 15 '15 at 13:08
source share

To develop a tiny bit in @Muzikant's answer and change it a bit to work on my device, try input keyevent 79 , a constant for KeyEvent.KEYCODE_HEADSETHOOK . Very rude:

  new Thread(new Runnable() { @Override public void run() { try { Runtime.getRuntime().exec( "input keyevent " + KeyEvent.KEYCODE_HEADSETHOOK ); } catch (Throwable t) { // do something proper here. } } }).start(); 

Forgive the pretty bad coding rules, I'm not too good at calling Runtime.exec () calls. Please note that my device is not deployed and I do not request root privileges.

The problem with this approach is that it only works under certain conditions (for me). That is, if I launched the above stream from the menu option that the user selects during a call, the call answers just fine. If I run it from a receiver that monitors the status of an incoming call, it is completely ignored.

So, on my Nexus 5, it works well for custom answers and should match the special setting of the call screen. It just wonโ€™t work for any automated applications like call management.

It should also be noted all possible reservations, including that this, too, is likely to stop working in an update or two.

+10
Nov 25 '14 at 21:52
source share

Below is an alternative approach that worked for me. It sends the key event to the telecommunications server directly using the MediaController API. This requires the BIND_NOTIFICATION_LISTENER_SERVICE application to allow and provide explicit granting of Notification access from the user:

 @TargetApi(Build.VERSION_CODES.LOLLIPOP) void sendHeadsetHookLollipop() { MediaSessionManager mediaSessionManager = (MediaSessionManager) getApplicationContext().getSystemService(Context.MEDIA_SESSION_SERVICE); try { List<MediaController> mediaControllerList = mediaSessionManager.getActiveSessions (new ComponentName(getApplicationContext(), NotificationReceiverService.class)); for (MediaController m : mediaControllerList) { if ("com.android.server.telecom".equals(m.getPackageName())) { m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); log.info("HEADSETHOOK sent to telecom server"); break; } } } catch (SecurityException e) { log.error("Permission error. Access to notification not granted to the app."); } } 

NotificationReceiverService.class in the above code may just be an empty class.

 import android.service.notification.NotificationListenerService; public class NotificationReceiverService extends NotificationListenerService{ public NotificationReceiverService() { } } 

In the relevant section of the manifest:

  <service android:name=".NotificationReceiverService" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.service.notification.NotificationListenerService" /> </intent-filter> 

Since the purpose of the event is explicit, this should probably avoid the side effects of starting a media player.

Note. After a call event, the communication server cannot be immediately active. In order for this to work reliably, it may be useful for the application to implement MediaSessionManager.OnActiveSessionsChangedListener to monitor when the telecommunications server becomes active before sending the event.

Update:

In Android O, you need to simulate ACTION_DOWN to ACTION_UP , otherwise it has no effect. that is, the following is necessary:

 m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); 

But since the official call to answer the call is available from Android O (see the main answer), you can no longer need this hack, unless you have the old compilation API level before Android O.

+8
May 14 '15 at 8:17
source share

Thanks @notz, the answer to me is working on Lolillop. In order for this code to work with the old Android SDK, you can make this code:

 if (Build.VERSION.SDK_INT >= 21) { Intent answerCalintent = new Intent(context, AcceptCallActivity.class); answerCalintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(answerCalintent); } else { if (telephonyService != null) { try { telephonyService.answerRingingCall(); } catch (Exception e) { answerPhoneHeadsethook(); } } } 
+1
May 11 '15 at 15:51
source share

How to turn on the speaker after answering calls automatically.

I solved the problem above using setSpeakerphoneOn. I think it's worth publishing here, since the option of using an answering machine for a phone call often also requires the use of a speakerphone. Thanks again to everyone on this topic, what a wonderful job.

This works for me on Android 5.1.1 on my Nexus 4 without ROOT .;)

Permission Required:

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

Java Code:

 // this means the phone has answered if(state==TelephonyManager.CALL_STATE_OFFHOOK) { // try and turn on speaker phone final Handler mHandler = new Handler(); mHandler.postDelayed(new Runnable() { @Override public void run() { AudioManager audioManager = (AudioManager) localContext.getSystemService(Context.AUDIO_SERVICE); // this doesnt work without android.permission.MODIFY_PHONE_STATE // audioManager.setMode(AudioManager.MODE_IN_CALL); // weirdly this works audioManager.setMode(AudioManager.MODE_NORMAL); // this is important audioManager.setSpeakerphoneOn(true); // note the phone interface won't show speaker phone is enabled // but the phone speaker will be on // remember to turn it back off when your done ;) } }, 500); // half a second delay is important or it might fail } 
+1
18 . '16 10:46
source share

adb adb

, Android - Linux JVM . , Linux- , . , ssh ( OpenVPN)

0
22 . '14 4:11
source share

root:

 input keyevent 5 

keyevents .

, , root .

0
23 . '14 11:17
source share

: , killCall(), answerCall(),

 <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission> public void killCall() { try { TelephonyManager telephonyManager = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); Class classTelephony = Class.forName(telephonyManager.getClass().getName()); Method methodGetITelephony = classTelephony.getDeclaredMethod("getITelephony"); methodGetITelephony.setAccessible(true); Object telephonyInterface = methodGetITelephony.invoke(telephonyManager); Class telephonyInterfaceClass = Class.forName(telephonyInterface.getClass().getName()); Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("endCall"); methodEndCall.invoke(telephonyInterface); } catch (Exception ex) { Log.d(TAG, "PhoneStateReceiver **" + ex.toString()); } } public void answerCall() { try { Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); } catch (IOException e) { answerRingingCallWithIntent(); } } public void answerRingingCallWithIntent() { try { Intent localIntent1 = new Intent(Intent.ACTION_HEADSET_PLUG); localIntent1.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); localIntent1.putExtra("state", 1); localIntent1.putExtra("microphone", 1); localIntent1.putExtra("name", "Headset"); getContext().sendOrderedBroadcast(localIntent1, "android.permission.CALL_PRIVILEGED"); Intent localIntent2 = new Intent(Intent.ACTION_MEDIA_BUTTON); KeyEvent localKeyEvent1 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK); localIntent2.putExtra(Intent.EXTRA_KEY_EVENT, localKeyEvent1); getContext().sendOrderedBroadcast(localIntent2, "android.permission.CALL_PRIVILEGED"); Intent localIntent3 = new Intent(Intent.ACTION_MEDIA_BUTTON); KeyEvent localKeyEvent2 = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK); localIntent3.putExtra(Intent.EXTRA_KEY_EVENT, localKeyEvent2); getContext().sendOrderedBroadcast(localIntent3, "android.permission.CALL_PRIVILEGED"); Intent localIntent4 = new Intent(Intent.ACTION_HEADSET_PLUG); localIntent4.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); localIntent4.putExtra("state", 0); localIntent4.putExtra("microphone", 1); localIntent4.putExtra("name", "Headset"); getContext().sendOrderedBroadcast(localIntent4, "android.permission.CALL_PRIVILEGED"); } catch (Exception e2) { e2.printStackTrace(); } } 
0
21 . '16 7:16
source share

FYI, , Android O, Valter Method 1: TelephonyManager.answerRingingCall() , , , endCall .

android.permission.CALL_PHONE .

Here is the code:

 // set the logging tag constant; you probably want to change this final String LOG_TAG = "TelephonyAnswer"; public void endCall() { TelephonyManager tm = (TelephonyManager) mContext .getSystemService(Context.TELEPHONY_SERVICE); try { if (tm == null) { // this will be easier for debugging later on throw new NullPointerException("tm == null"); } // do reflection magic tm.getClass().getMethod("endCall").invoke(tm); } catch (Exception e) { // we catch it all as the following things could happen: // NoSuchMethodException, if the answerRingingCall() is missing // SecurityException, if the security manager is not happy // IllegalAccessException, if the method is not accessible // IllegalArgumentException, if the method expected other arguments // InvocationTargetException, if the method threw itself // NullPointerException, if something was a null value along the way // ExceptionInInitializerError, if initialization failed // something more crazy, if anything else breaks // TODO decide how to handle this state // you probably want to set some failure state/go to fallback Log.e(LOG_TAG, "Unable to use the Telephony Manager directly.", e); } } 
0
24 . '17 18:10
source share



All Articles