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.
ThreeFingerSwipeDetector
exactly do, code wise? Doesdetector.onTouchEvent(event)
currently ever returnfalse
? 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 overridingonInterceptTouchEvent()
in stead ofonTouchEvent()
. – MichaelisThreeFingerSwipeDetector
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 overwriteonInterceptTouchEvent(Event event)
nothing happens at all, since it seems this method is only called once instead ofonTouchEvent(Event event)
which is called frequently. – Presume