How can a service listen for touch gestures/events?

37,130

Solution 1

I had this same problem and I've finally figured it out! Thanks to this post: Creating a system overlay window (always on top). You need to use an alert window instead of an overlay (and this also means you can use it in 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);

Then just attach a GestureListener in this manner:

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!

Solution 2

Interesting question. I don't know how they did that and I found google group posts which tell me that there is no global touch listener. But I have an idea anyways...

I found this post where someone succeeds to display a popupwindow from a service. If I would make that popup transparent and fullscreen, I'm sure I could capture the touches since I'm allowed to set a touch interceptor.

Edit: Please report results when you try that, would be interesting to know if this works...

Solution 3

I tested this on API 21 and a nexus 5 and I was able to log, from a service, when a touch event was fired by the system. However, the data inside the MotionEvent object, for example coordinates, returns 0.0 when OUTSIDE of what seems to be my app's package.

Two sources integration, permission

I'm curious as to why the event.getX(), event.getY() and event.getPressure() return 0.0 when not in an activity of the app where the service lives.

Edit

This solution does not prevent other listeners from receiving the touch event capured by the service because of

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

By returning false, it allows other listeners to receive the event.

Edit2

Apparently, the input dispatcher in the OS will set the coordinates and pressure to 0 if the current activity and the listener do not share an UID, here is source

Solution 4

I tested every possible solution but nothing worked some didn't fired touch event which did they frozed the screen .

So I did some reverse engineering and now posting solution which works

  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);
Share:
37,130
Brian
Author by

Brian

Updated on April 12, 2020

Comments

  • Brian
    Brian about 4 years

    I'm wondering how apps like SwipePad and Wave Launcher are able to detect touch gestures/events simply through a service. These apps are able to detect a touch gestures even though it is not in their own Activity. I've looked all over the Internet and haven't found how they can do that.

    My main question is how a service can listen in on touch guestures/events just as a regular Activity may receive MotionEvents even though it may not be in the original Activity or context. I'm essentially trying a build an app that will recongize a particular touch gesture from a user regardless which Activity is on top and do something when that gesture is recongized. The touch recongition will be a thread running in the background as a service.