【问题标题】:Programmatically accept call in Nougat以编程方式接受 Nougat 中的呼叫
【发布时间】:2017-05-23 08:57:37
【问题描述】:

从一年开始,我一直在研究物联网产品,附加的应用程序运行良好。现在我无法在更高版本的android中以编程方式接受调用。功能对产品来说非常重要。非常感谢任何帮助。

在安全补丁更新2016 年 11 月之前,Runtime.getRunTime.exec("Command") 可以正常工作以通过编程方式接受呼叫。

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

如何在 Nougat 版本的 android 中实现。

寻找任何形式的黑客攻击。

我已经为增强功能打开了一个线程。

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

注意* 如果你们中的任何人面临同样的问题,请向Android Dev Team 申请加入并提供获得用户运行时许可的条款。按照上面提到的 URL 请求。

【问题讨论】:

标签: android android-7.0-nougat android-security android-7.1-nougat


【解决方案1】:

由于我也在研究物联网产品,这是我面临的最大问题之一,但经过一些研究,我想我已经找到了解决这个问题的方法,或者你可以说一个简单的 hack。 我已经在几个版本的设备上测试了这个 hack,发现大多数设备都有响应。只有三星设备没有响应,一些华为设备和一些 Oppo 设备也没有响应。(我也在寻找这些设备的东西)。

我注意到 Android 提供了访问通知的一项功能。您可以使用 NotificationListenerService 来读取通知并对它们执行一些操作。 它提供了一些覆盖方法:

 onNotificationPosted()
    onNotificationRemoved()
    getActiveNotifications()

...等

这是一个代码: 创建一个扩展 NotificationListenerService 的服务

 class NLService extends NotificationListenerService {

     @Override
     public void onNotificationPosted(StatusBarNotification sbn) {
       ....
     }

     @Override
     public void onNotificationRemoved(StatusBarNotification sbn) {
       ....
     }

在 AndroidMenifest 中,将此服务添加为:

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

这将允许您的应用程序读取收到的任何通知。

现在,这里是主要代码:

在 onNotificationPosted(StatusBarNotification sbn) 中添加以下代码:

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

就是这样!

一切就绪,运行应用程序和除三星以外的设备,无论哪个显示来电通知,带有接听和拒绝/拒绝操作按钮,都可以接听电话。

要打开通知访问设置并允许您的应用程序读取通知,请使用:

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

只需为此创建一个 POC,然后告诉我它是如何工作的。

如果有帮助,请标记我的答案。

另外,如果您可以针对三星设备提供相同的解决方案,请更新。

谢谢

【讨论】:

  • 在我的三星 Note 2 Android v7.1.1 上完美运行!谢谢!
  • 完美运行,但如果我想用按钮回答它怎么办?不是自动回答
  • 可以使用一个简单的场景。请查看我的新答案。
  • 嗨,三星的问题你解决了吗?我想三星使用他们的丰富通知sdk。但我不知道如何处理它
【解决方案2】:

这是一种黑客攻击,您可以使用accessibility service 接听电话。要启用无障碍服务,您必须在设置 - 无障碍 - 您的服务中启用您的服务。

首先,将 typeWindowContentChanged 添加到 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"
/>

并对事件或“显示的文本”或“内容描述”做一些事情。

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

是的,我知道这不是解决您问题的好方法。这是一种黑客行为。

【讨论】:

  • @Stanely 我正在尝试与您在帖子中写的相同,但是当接到电话时,我没有在 onAccessibilityEvent 中收到任何事件。您能否展示您的完整示例。
  • @user565 您是否从设置菜单中打开了辅助功能选项?您可以查看developer.android.com/guide/topics/ui/accessibility/service 了解无障碍服务。此外,您必须使用 android 版本 1.6 或更高版本。
  • 无障碍服务可以做任何事情,但使用它来响应呼叫是一种黑客行为。所以我不建议你这样做。
  • 好吧,我实际上使用 NotificationListenerService 进行了测试,它工作正常,但我使用 NotificationListenerService 面临的唯一问题是用户需要手动注册监听器,我想通过应用程序来做到这一点(我有一个系统应用程序)。然后我开始使用辅助功能服务来研究你的方式,有趣的是我可以使用这种方式以编程方式注册我的应用程序:
  • Settings.Secure.putString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "myPackage/myService"); Settings.Secure.putString(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, "1");
【解决方案3】:

要使用按钮接听电话,请在检测到来电时设置一个标志:

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

现在,在您的 NSLogService 类中创建一个列表,

static ArrayList<StatusBarNotification> statusBarNotifications;

并在您的 onNotificationPosted() 中将 StatusBarNotification 添加到列表中,

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

在您的主屏幕中,点击按钮,拨打performNotificationOperation(NLService.getAllNotifications());

这里是这个方法的定义:

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

}

【讨论】:

    【解决方案4】:

    根据“Vishal Sharma”的回答,我们可以动态获取动作按钮标题,以支持其他语言:

      @Override
      public void onNotificationPosted(StatusBarNotification sbn) {
        try {
          if (sbn.getNotification().actions != null) {
            Notification.Action[] notificationAction=sbn.getNotification().actions;
            //Log.e(G.TAG, "" +notificationAction  + " =>"+notificationAction.length);
               String rejectTitle=""+notificationAction[0].title;
               String acceptTitle=""+notificationAction[1].title;
    
            for (Notification.Action action : notificationAction){
              if (action.title.toString().equalsIgnoreCase(acceptTitle)) {
                PendingIntent intent = action.actionIntent;
                try {
                  intent.send();
                } catch (PendingIntent.CanceledException e) {
                  e.printStackTrace();
                }
              }
            }
    
    
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-05
      • 2019-02-03
      • 1970-01-01
      • 2013-10-17
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多