Programmatically accept a call in Nougat

Since one year I have been working on the IOT product, and the application is attached to work. Now I can not accept the call programmatically in higher versions of Android. Feature is very important for the product. Any help is appreciated.

Prior to the November 2016 security update update, Runtime.getRunTime.exec("Command") worked fine to receive the call programmatically.

 Runtime.getRuntime().exec("input keyevent " +Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); 

How to make this possible in the Nougat version for Android.

Looking for some hack.

I opened the thread for improvements.

https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened&groupby=&sort=&id=231938

Note * If any of you are faced with the same problem, please ask Android Dev Team to enter it and provide an opportunity to get permission at runtime by the user. Follow the above to specify the URL for the request.

+18
android android-7.0-nougat android-7.1-nougat android-security
Jan 09 '17 at 6:35
source share
3 answers

Since I am also working on an IOT product, this was one of the biggest problems I encountered, but after some research, I believe that I found some solution to this problem, or you can say a simple hack. I tested this hack on multiple devices with multiple versions and found that most devices respond. Only Samsung devices are not responding, some Huawei devices and some Oppo devices are also not responding (I'm still watching something for these devices too).

I noticed that Android provides one of the "Notification Access" features. You can use NotificationListenerService to read notifications and perform some actions on them. It provides some override methods:

  onNotificationPosted() onNotificationRemoved() getActiveNotifications() 

... etc.

Here is the code: Create a service that extends NotificationListenerService

  class NLService extends NotificationListenerService { @Override public void onNotificationPosted(StatusBarNotification sbn) { .... } @Override public void onNotificationRemoved(StatusBarNotification sbn) { .... } 

In AndroidMenifest add this service as:

  <service android:name=".NLService" android:label="@string/app_name" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> <intent-filter> <action android:name="android.service.notification.NotificationListenerService" /> </intent-filter> </service> 

This will allow your application to read the notifications received.

Now, here is the main code:

In onNotificationPosted (StatusBarNotification sbn) add this code:

  @Override public void onNotificationPosted(StatusBarNotification sbn) { try { if (sbn.getNotification().actions != null) { for (Notification.Action action : sbn.getNotification().actions) { Log.e(TAG, "" + action.title); if (action.title.toString().equalsIgnoreCase("Answer")) { Log.e(TAG, "" + true); PendingIntent intent = action.actionIntent; try { intent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } } } } catch (Exception e) { e.printStackTrace(); } } 

Here it is!

Everything is installed. Launch the application and devices, with the exception of Samsung, depending on what displays an incoming call notification with the Answer and Reject / Cancel buttons, you can answer the call.

To open the Notification Access Settings and let your application read the notification, use:

  Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); startActivity(intent); 

Just create a POC for this and let me know how it works.

Please mark my answer if this helps.

In addition, if you can provide some solution on this subject regarding Samsung devices, please update.

thank

+6
Apr 6 '17 at 12:09 on
source share

To answer a call with the button, set the flag when an incoming call is detected:

  if(state==TelephonyManager.CALL_STATE_RINGING){ shouldAnswerCallViaNotification = true; } else { shouldAnswerCallViaNotification = false; } 

Now create a list in your NSLogService class,

 static ArrayList<StatusBarNotification> statusBarNotifications; 

and in your onNotificationPosted () add StatusBarNotification to the list,

  @Override public void onNotificationPosted(StatusBarNotification sbn) { if (HomeScreen.shouldAnswerCallViaNotification) { if (statusBarNotifications == null) { updateNotificationList(); } statusBarNotifications.add(sbn); } else { updateNotificationList(); } } public static ArrayList<StatusBarNotification> getAllNotifications() { return statusBarNotifications; } public static void updateNotificationList() { if (statusBarNotifications != null) statusBarNotifications = null; statusBarNotifications = new ArrayList<StatusBarNotification>(); } 

In your HomeScreen, click the button performNotificationOperation(NLService.getAllNotifications());

here is the definition of this method:

  private void performNotificationOperation(ArrayList<StatusBarNotification> activeNotifications) { if (activeNotifications.size()> 0) { main_Loop: for (StatusBarNotification notification : activeNotifications) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (notification.getNotification().actions != null) { for (Notification.Action action : notification.getNotification().actions) { // Log.e(TAG, "" + action); Log.e(TAG, "" + action.title); if (action.title.toString().equalsIgnoreCase("Answer")) { Log.e(TAG, "" + true); PendingIntent intent = action.actionIntent; try { intent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } break main_Loop; } } } } } catch (Exception e) { e.printStackTrace(); } } } try { NLService.updateNotificationList(); } catch (Exception e) { e.printStackTrace(); } } 
+1
Jun 29 '17 at 9:41 on
source share

This is a kind of hack, you can use the accessibility service to receive a call. To enable the availability service, you must enable your service in the settings - Availability - Your service.

First add the typeWindowContentChanged for accessibilityEventTypes.

 <accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewFocused|typeViewScrolled|typeWindowContentChanged|typeWindowStateChanged" android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity" android:canRetrieveWindowContent="true" /> 

And do something with the event or “display text” or “content description”.

 @Override public void onAccessibilityEvent(AccessibilityEvent event) { // Do something with Click or Focused event final int eventType = event.getEventType(); String eventText = null; switch(eventType) { case AccessibilityEvent.TYPE_VIEW_CLICKED: eventText = "Focused: "; break; case AccessibilityEvent.TYPE_VIEW_FOCUSED: eventText = "Focused: "; break; } eventText = eventText + event.getContentDescription(); // Traverse all items in screen. // Do something with text. AccessibilityNodeInfo info = getRootInActiveWindow(); int index; int count = info.getChildCount(); AccessibilityNodeInfo child; for (index = 0; index < count; index++) { child = info.getChild(index); if (child.getText() != null) Log.d(TAG, "text: " + child.getText().toString() + " " + child.getContentDescription()); // perform Click //if (child.isClickable()); //child.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } 

Yes, I know that this is not an elegant way to solve your problem. This is a kind of hack.

0
Feb 21 '17 at 10:12
source share



All Articles