web-dev-qa-db-fra.com

Accepter un appel programmé au Nougat

Depuis un an, je travaille sur un produit IOT et l’application jointe fonctionne bien. Maintenant, je ne suis pas en mesure d'accepter les appels par programmation dans les versions supérieures d'Android. La fonctionnalité est très importante pour le produit. Toute aide est grandement appréciée.

Avant la mise à jour du correctif de sécurité novembre 2016, Runtime.getRunTime.exec("Command") fonctionnait correctement pour accepter les appels par programmation. 

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

Comment rendre cela possible dans la version Nougat d'Android.

Vous recherchez une sorte de bidouille. 

J'ai ouvert un fil pour les améliorations. 

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

Note * Si l’un d’entre vous est confronté au même problème, veuillez demander à Android Dev Team de le saisir et prévoir l’obtention de l’autorisation d’exécution par l’utilisateur. Suivez l'URL mentionnée ci-dessus pour demander.

19
AndroidHacker

Comme je travaille également sur le produit IOT, c’est l’un des plus gros problèmes auquel j’ai été confronté, mais après quelques recherches, je pense avoir trouvé une solution à ce problème, ou vous pouvez dire un simple bidouillage . J'ai testé ce bidouillage dans plusieurs appareils avec plusieurs versions, et a constaté que la plupart des appareils répondent. Seuls les appareils Samsung ne répondent pas, certains appareils Huawei et certains appareils Oppo ne répondent pas non plus (je cherche encore quelque chose pour ces appareils).

J'ai remarqué qu'Android fournit une fonctionnalité d'accès aux notifications. Vous pouvez utiliser NotificationListenerService pour lire les notifications et exécuter certaines actions sur celles-ci . Il fournit des méthodes de remplacement:

 onNotificationPosted()
    onNotificationRemoved()
    getActiveNotifications()

... etc

Voici un code: Créez un service qui étend NotificationListenerService

 class NLService extends NotificationListenerService {

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

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

Dans AndroidMenifest, ajoutez ce service en tant que:

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

Cela permettra à votre application de lire toute notification reçue.

Maintenant, voici le code principal:

Dans onNotificationPosted (StatusBarNotification sbn), ajoutez ce 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();
          }
     }

C'est tout!

Tout est défini. Exécutez l'application et les appareils, à l'exception de Samsung, qui affiche une notification pour un appel entrant, avec les boutons Répondre et Refuser/Refuser, vous permettront de répondre à un appel.

Pour ouvrir les paramètres d'accès à la notification et permettre à votre application de lire la notification, utilisez:

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

Créez simplement un POC pour cela et laissez-moi savoir comment cela fonctionne.

S'il vous plaît marque ma réponse si cela aide.

De même, si vous pouviez fournir une solution au même problème concernant les appareils Samsung, veuillez mettre à jour.

Merci

8
Vishal Sharma

C'est une sorte de bidouille, vous pouvez utiliser service d'accessibilité pour recevoir un appel. Pour activer le service d'accessibilité, vous devez activer votre service dans Configuration - Accessibilité - Votre service.

Tout d'abord, ajoutez 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"
/>

Et faites quelque chose avec événement ou "texte affiché" ou "description du contenu".

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

Oui, je sais que ce n'est pas une façon élégante de résoudre votre problème. C'est une sorte de bidouille.

0
Stanley Kou

Pour répondre à un appel à l'aide d'un bouton, définissez un indicateur lorsqu'un appel entrant est détecté:

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

Maintenant, créez une liste dans votre classe NSLogService,

static ArrayList<StatusBarNotification> statusBarNotifications;

et dans votre onNotificationPosted (), ajoutez StatusBarNotification à une liste,

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

Dans votre écran d’accueil, en cliquant sur le bouton, appelez performNotificationOperation(NLService.getAllNotifications());

voici une définition pour cette méthode:

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

}
0
Vishal Sharma

Selon " Vishal Sharma ", vous pouvez obtenir le titre du bouton d'action de manière dynamique, pour prendre en charge d'autres langues:

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