Программно принять звонок в Нуга
С одного года я работал над продуктом IOT, и приложение работало нормально. Теперь я не могу принять вызов программно в более высоких версиях Android. Особенность очень важна для продукта. Любая помощь высоко ценится.
Перед обновлением для системы безопасности ноябрь 2016 г. Runtime.getRunTime.exec("Command")
работал нормально, чтобы принять вызов программно.
Runtime.getRuntime().exec("input keyevent " +Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
Как сделать это возможным в нуг версии андроида.
Ищу какой-нибудь взломать.
Я открыл ветку для улучшений.
Примечание * Если кто-то из вас сталкивается с той же проблемой, пожалуйста, попросите Android Dev Team
войти в него и предоставить возможность для получения разрешения во время выполнения пользователем. Следуйте вышеупомянутому URL для запроса.
4 ответа
Поскольку я также работаю над продуктом IOT, это была одна из самых больших проблем, с которыми я столкнулся, но после некоторых исследований, я думаю, я нашел какое-то решение этой проблемы, или вы можете сказать простой взлом. Я проверил этот взлом на нескольких устройствах с несколькими версиями и обнаружил, что большинство устройств отвечает. Только устройства Samsung не отвечают, некоторые устройства Huawei и некоторые устройства 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();
}
}
Это оно!
Все установлено, Запустите приложение и устройства, кроме Samsung, в зависимости от того, что показывает уведомление о входящем звонке, с кнопками "Ответить" и "Отклонить / Отклонить действие", вы сможете ответить на звонок.
Чтобы открыть параметры доступа к уведомлениям и разрешить приложению читать уведомления, используйте:
Intent intent = new
Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(intent);
Просто создайте POC для этого и дайте мне знать, как это работает.
Пожалуйста, отметьте мой ответ, если это поможет.
Кроме того, если вы могли бы предложить какое-то решение для того же устройства Samsung, пожалуйста, обновите.
Спасибо
Это своего рода хак, вы можете использовать сервис доступности для приема звонков. Чтобы включить службу специальных возможностей, вы должны включить ее в меню "Настройка" - "Специальные возможности - Ваша служба".
Сначала добавьте 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);
}
}
Да, я знаю, что это не изящный способ решить вашу проблему. Это своего рода хак.
Согласно ответу "Вишал Шарма" мы можем динамически получать заголовок кнопки действия для поддержки других языков:
@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();
}
}
Для ответа на вызов с помощью кнопки установите флажок при обнаружении входящего вызова:
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();
}
}