web-dev-qa-db-fra.com

Comment un service peut-il écouter les gestes/événements tactiles?

Je me demande comment des applications telles que SwipePad et Wave Launcher sont capables de détecter des gestes/événements tactiles simplement via un service. Ces applications sont capables de détecter des gestes tactiles même si ce n'est pas dans leur propre activité. J'ai regardé partout sur Internet et je n'ai pas trouvé comment ils peuvent le faire. 

Ma question principale est de savoir comment un service peut écouter des invités/événements tactiles de la même manière qu'une activité normale peut recevoir MotionEvents même si elle ne se trouve pas dans l'activité ou le contexte d'origine. J'essaie essentiellement de créer une application qui va recongeler un geste particulier d'un utilisateur, quelle que soit l'activité qui est au dessus, et faire quelque chose lorsque ce geste est reconnu. La reconnaissance tactile sera un fil exécuté en arrière-plan en tant que service.

60
Brian

J'ai eu le même problème et je l'ai enfin compris! Grâce à cet article: Création d’une fenêtre de superposition système (toujours au-dessus) . Vous devez utiliser une fenêtre d'alerte au lieu d'une superposition (cela signifie également que vous pouvez l'utiliser dans Andoid ICS):

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);

Ensuite, attachez simplement un GestureListener de cette manière:

GestureDetector gestureDetector = new GestureDetector(this, new AwesomeGestureListener());
View.OnTouchListener gestureListener = new View.OnTouchListener() {
      public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
      }
};

overlayView.setOnTouchListener(gestureListener);

Yay!

18
pypmannetjies

Question interessante. Je ne sais pas comment ils l'ont fait et j'ai trouvé des posts sur les groupes de Google qui m'indiquent qu'il n'y a pas d'auditeur tactile global. Mais j'ai quand même une idée ...

J'ai trouvé ce post où quelqu'un réussit à afficher une fenêtre contextuelle à partir d'un service. Si je voulais que cette fenêtre contextuelle soit transparente et plein écran, je suis sûr que je pourrais capturer les contacts puisque je suis autorisé à définir un touch interceptor .

Edit: S'il vous plaît rapporter les résultats lorsque vous essayez cela, il serait intéressant de savoir si cela fonctionne ...

5
Knickedi

J'ai testé toutes les solutions possibles, mais rien n'a fonctionné. Certains n'ont pas déclenché l'événement tactile qui a effacé l'écran.

J'ai donc fait de l'ingénierie inverse et postant maintenant une solution qui fonctionne 

  WindowManager.LayoutParams params = new Android.view.WindowManager.LayoutParams(0, 0, 0, 0, 2003, 0x40028, -3);
        View mView = new View(this);

        mView.setOnTouchListener(this);

        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
3
Mr Coder

J'ai testé cela sur API 21 et sur un lien 5 et j'ai pu me connecter, à partir d'un service, lorsqu'un événement tactile était déclenché par le système. Cependant, les données à l'intérieur de l'objet MotionEvent, par exemple les coordonnées, renvoient 0.0 lorsqu'EXTÉRIEUR de ce qui semble être le package de mon application.

Deux sources l'intégration , autorisation

Je suis curieux de savoir pourquoi les événements event.getX (), event.getY () et event.getPressure () renvoient 0,0 lorsqu'ils ne sont pas dans une activité de l'application où le service réside.

Modifier

Cette solution n’empêche pas d’autres auditeurs de recevoir l’événement tactile pris en charge par le service en raison de

public boolean onTouch(View v, MotionEvent e){
    Log.d(LOG_TAG, "Touch event captured");
    return false;      

En retournant false, cela permet aux autres auditeurs de recevoir l'événement.

Edit2

Apparemment, le répartiteur d’entrée dans le système d’exploitation fixera les coordonnées et la pression à 0 si l’activité en cours et l’auditeur ne partagent pas un UID. Voici source

3
Clocker

J'ai effectué une recherche dans de nombreux SO threads, mais pour des raisons de sécurité, je ne pense pas que cela soit possible pour tous les packages du système. C'est certainement pour votre propre application cependant.

WindowManager

 WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);

Mise en page flottante/superposée

floatyView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate
            (R.layout.floating_view, null);

    floatyView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.d(TAG, "event.x " + event.getX());
            Log.d(TAG, "event.y " + event.getY());
            if (event.getAction() == MotionEvent.ACTION_UP) {
                v.performClick();
            }
            return false;
        }
    });

Disposition

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
   Android:background="@Android:color/transparent"
   Android:layout_width="wrap_content"
   Android:layout_height="wrap_content"/>
0
John61590