2017-09-13 4 views
1

J'essaie d'envoyer un événement de presse arrière du système via le AccessibilityService et cela fonctionne très bien, mais seulement si je ne suis pas dans ma propre application. Je reçois toujours true de performGlobalAction, peu importe si je suis dans ma propre application ou non, mais je vois seulement que l'événement est vraiment exécuté si je ne suis pas dans ma propre application mais dans toute autre application (dans le sens où l'activité précédente est montrée ou similaire)AccessibilityService - performGlobalAction ne fonctionne pas dans sa propre application

Des idées pour lesquelles cela se produit? Mon application est une application de barre latérale avec une superposition dessinée en haut dans le WindowManager et tout fonctionne (AccessibilityService est en cours d'exécution et gère mes événements personnalisés et le service renvoie toujours des messages de réussite pour mes événements, mais ma propre application ne réagit pas à l'arrière événement de bouton).

Mon service ressemble à ce qui suit:

public class MyAccessibilityService extends AccessibilityService { 

    public static void sendBackIntent(Context context) { 
     Intent intent = new Intent(context, MyAccessibilityService.class); 
     intent.putExtra("action", GLOBAL_ACTION_BACK); 
     context.startService(intent); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Bundle extras = intent.getExtras(); 
     Integer action = null; 
     if (extras != null) { 
      action = extras.getInt("action"); 
     } 

     if (action != null) { 
      switch (action) { 
       case GLOBAL_ACTION_BACK: 
        boolean result = performGlobalAction(action); 
        L.d("Action %d executed: %b", action, result); 
        break; 
       default: 
        L.e("Unhandled action %d", action); 
        break; 
      } 
     } 
     return super.onStartCommand(intent, flags, startId); 
    } 

    @Override 
    public void onAccessibilityEvent(AccessibilityEvent event) { 

    } 

    @Override 
    public void onInterrupt() { 
    } 
} 

Modifier

Pour que ce soit clair:

  • Je ne commence pas ce service via MyAccessibilityService.sendBackIntent(context), j'envoie l'intention comme suit : if (isAccessibilityserviceRunning) MyAccessibilityService.sendBackIntent(context)
  • Je commence mon service via le système J'ai activé le menu de service en l'activant simplement et en le laissant ensuite démarrer automatiquement
  • J'ai tout paramétré pour le AccessibilityService dans un accessibilityservice.xml et je l'utilise pour définir mes paramètres de services et cela fonctionne parfaitement bien, tous les événements I veulent recevoir sont reçus de manière fiable et correcte

EDIT 2

on dirait que dans mon cas, ma superposition est en train de voler encore l'accent rendant focalisable et non a des problèmes de synchronisation qui font parfois des problèmes. Pourtant, ma solution peut être améliorée en utilisant BroadcastReceiver pour communiquer avec le service, comme l'appel startService n'est pas sûr comme indiqué dans la réponse

Répondre

1

accepté Il me semble que vous faites des choses très étranges. Il semble que vous traitez votre AccessibilityService comme un Service normal. La partie de ce qui suggère ceci est votre mise en œuvre des éléments suivants aux méthodes:

public static void sendBackIntent(Context context); 

@Override 
public int onStartCommand(Intent intent, int flags, int startId); 

Juste par les signatures de ces deux méthodes et votre appel de

context.startService(intent);  

Au sein de votre méthode statique, je peux dire que vous ne comprenez pas AccessibilityServices et comment ils sont censés effectuer leur travail. Vous ne pouvez pas démarrer votre service d'accessibilité, ni interagir avec celui-ci, comme vous le faites. Vous pouvez certainement utiliser les services d'accessibilité pour effectuer des actions globales, mais ils ne le feront pas correctement et globalement, à moins que vous ne les lanciez correctement, à partir du menu Accessibility Services (vous connaissez celui où TalkBack apparaît).

Votre code essentiellement, ne fonctionne pas dans le contexte que vous pensez qu'il fonctionne. Donc, il fonctionne, et fait des choses. Mais, AccessibilityServices et leur puissance respective, est dans leur capacité à se connecter globalement au système d'exploitation.L'API d'Android ne se lient pas un AccessibilityService correctement, lorsque vous essayez de lancer votre service avec:

context.startService(intent); 

Vous devez lancer votre service d'accessibilité dans le menu Paramètres Services d'accessibilité.

Même si votre service est déjà lancé, un tel appel est dangereux! Il n'y a aucune garantie que vos utilisateurs vont démarrer le service avant d'ouvrir votre activité. Une fois que vous avez appelé context.startService et tenté de démarrer votre AccessibilityService de cette manière, cela empêchera le menu Paramètres d'accessibilité de démarrer votre service et de lier correctement le système d'exploitation. En fait, une fois dans cette situation un utilisateur devrait: Désactiver le commutateur pour votre service dans le menu Paramètres d'accessibilité, forcer l'arrêt (peut-être même désinstaller) votre application, redémarrer leur appareil, démarrer votre service et ensuite commencer votre activité, ordre pour le bon comportement à atteindre. Si vous ne le faites pas, il ne se liera pas correctement au système d'exploitation et son comportement est indéfini. À l'heure actuelle, vous avez essentiellement créé un hack dans le système d'exploitation et vous êtes confronté à ce comportement indéfini, qui peut varier considérablement d'une version, d'un fabricant à l'autre, car son comportement n'est pas couvert par les tests d'intégration AOSP. En fait, vous NE POUVEZ PAS lancer explicitement les services d'accessibilité à l'aide de l'appel context.startService(). Il s'agit d'une fonctionnalité de sécurité très importante d'Android, car les services d'accessibilité peuvent accéder au contenu de l'écran, et les utilisateurs ont besoin d'un contrôle précis des fournisseurs et des applications auxquels ils autorisent cet accès. Donc, bien que vous ayez CERTAINS comportements, il s'agit d'un comportement non défini et dangereux. Ce que vous voulez quelque chose comme ce qui suit:

Avec le XML de configuration de service suivant:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" 
    android:description="@string/accessibility_service_description" 
    android:accessibilityEventTypes="typeWindowContentChanged" 
    android:accessibilityFlags="flagRequestTouchExplorationMode" 
    android:canRetrieveWindowContent="true" 
    android:canRequestTouchExplorationMode="true" 
    android:accessibilityFeedbackType="feedbackGeneric" 
    android:notificationTimeout="100" 
    android:settingsActivity="com.service.SettingsActivity" 
    /> 

Et le service d'accessibilité suivant.

class MyA11yService extends AccessibilityService { 
    @Override public boolean onGesture(int gestureId) { 
     switch (gestureId) { 
      case GESTURE_SWIPE_UP_AND_DOWN: 
       CLog.d("Performing gesture."); 
       performGlobalAction(GLOBAL_ACTION_BACK); 
       return true; 

      default: 
       return false; 
     } 
    } 
} 

Les travaux performGlobalAction appel très bien dans tous les Context. Maintenant, au lieu d'effectuer cette action sur le geste SWIPE_UP_DOWN, ce que vous voulez faire est de mettre en place une sorte de communication inter-processus avec la partie de celle-ci que vous voulez pouvoir déclencher l'action "bouton global back". Mais, cette information est pour une autre question, mais si vous comprenez l'information dans ce post, je suis sûr que la façon dont vous devez procéder sera claire.

+1

Les commentaires ne concernent pas les sessions de discussion ou de débogage étendues; cette conversation a été [déplacée pour discuter] (http://chat.stackoverflow.com/rooms/154466/discussion-on-answer-by-chriscm-accessibilityservice-performglobalaction-not-w). S'il y a des informations importantes ici, elles devraient être éditées dans la question ou la réponse. –

+0

Donc, à un certain moment dans cette menace, j'ai posté un commentaire sur la suppression des commentaires après avoir déplacé une partie de ce contenu. Quelqu'un l'a nuké cependant et maintenant c'est parti. Des avertissements avant de supprimer autant de contenu seraient appréciés. @ prom85: si vous avez une autre question à poser sur un autre post, je pense que c'est la bonne réponse (ou du moins l'information qui doit être vue par d'autres personnes confondues avec des problèmes similaires) pour cette question particulière. – ChrisCM

+0

Je ne vois rien de ce que vous avez posté à ce sujet parmi les commentaires supprimés. Quoi qu'il en soit, l'information n'a pas été * effacée *; il a été archivé dans le chat. Il n'y a pas vraiment de moyen de vous en avertir sauf de laisser un autre commentaire bruyant, ce que nous sommes fortement découragés de faire. Nous obtenons des drapeaux automatiques lorsqu'un fil de commentaire devient trop long, et le plan d'action suggéré est de le déplacer pour discuter. Si vous avez des suggestions sur la façon d'améliorer le flux de travail, ou un problème avec la politique, vous pouvez poster une question sur [Meta]. La ligne que vous allez obtenir est fondamentalement que les commentaires sont temporaires et non pour la discussion. –