Overlay App that reacts only on some touch events
Asked Answered
P

1

2

I'm currently diving into Android development and recently came up against a difficulty. I'd like to create an overlay app, which lies on top of all other apps. It should listen for a three finger swipe, whereas all other Touch Events should be handled by the OS (e.g. an underlying app).

Is that even possible?

I already found out that I need to add the LayoutParam TYPE_PHONE instead of SYSTEM_ALERT since the latter one will consume all touch events. So my class looks like this now:

package [...]

public class Overlay extends Service {

    private TView mView;
    private ThreeFingerSwipeDetector detector = new ThreeFingerSwipeDetector() {

        @Override
        public void onThreeFingerTap() {
            Toast.makeText(getBaseContext(), "Three Fingers recognized.", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(getBaseContext(), "Launched! :-)", Toast.LENGTH_SHORT).show();

        mView = new TView(this);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                // PHONE, because SYSTEM_ALERT will consume _ALL_ touch events
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                      | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                      | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }



    @Override
    public void onDestroy() {
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.removeView(mView);
        mView = null;
        super.onDestroy();
    }





    // inner class 
    class TView extends ViewGroup {

        public TView(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
        }

        @Override
        protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
        }



        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if(detector.onTouchEvent(event)) {
                return true;
            }

            //TODO: what am I supposed to do when it's not a 3 finger swipe (aka the detector doesn't recognize it as one)
// something like super.onInterceptTouchEvent(event) or so?
            }
    }
    }

The detector will correctly detect a 3 finger swipe but my app in its current state will block all other user interaction with the underlying UI until I kill the app.

Is there any system call that can be called with MotionEvent as parameter where my TODO annotation is now? Or do I want something that is just not possible?

Best regards and thank you very much!

Edit: The ThreeFingerSwipeDetector Class looks like this:

[Import, ...]    
public abstract class ThreeFingerSwipeDetector {


    public boolean onTouchEvent(MotionEvent event) {
        int t = event.getActionMasked();
        switch(event.getActionMasked()) {
        case MotionEvent.ACTION_POINTER_DOWN:
            if(event.getPointerCount() == 3)
                onThreeFingerTap();
                return true;
        case MotionEvent.ACTION_DOWN:
            if(event.getPointerCount() == 3)  {
                onThreeFingerTap();
                return true;
        }               
      }

        return false;
    }

    public abstract void onThreeFingerTap();
}

Actually it's not a swipe recognizer yet but it only checks for three finger taps for now. Anyways the logic in there should be quite the same.

Presume answered 18/9, 2014 at 16:25 Comment(2)
What does ThreeFingerSwipeDetector exactly do, code wise? Does detector.onTouchEvent(event) currently ever return false? I imagine it may not, which could explain why any and all touch events are consumed until you kill your app. Alternatively, you may want to decide whether or not to do something with a touch event by overriding onInterceptTouchEvent() in stead of onTouchEvent().Michaelis
So I just added the ThreeFingerSwipeDetector in my original post. It doesn't recognize a swipe but a 3 finger tap yet, but that shouldn't change anything for now. I also debugged it and it actually returned false when I touched the screen with less than 3 fingers. When I overwrite onInterceptTouchEvent(Event event) nothing happens at all, since it seems this method is only called once instead of onTouchEvent(Event event) which is called frequently.Presume
P
0

I'll answer my own question: It's simply not possible. According to THIS post and the Android documentation you can either consume all touch events or none since version 4.0.3. So it's not possible to handle only some touch events and to let others go through the overlay.

Presume answered 20/9, 2014 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.