问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/25917844/overlay-app-that-reacts-only-on-some-touch-events