Preventing parallel motion event dispatching from view system and event proxy
1) When view system is already dispatching an event, proxy-dispatch is restricted
to gesture only and follow the gesture dispatching rule.
2) If a full-proxy-dispatch is going on, and view-dispatch comes in, view-dispatch
takes over and proxy-dispatch is cancelled.
3) During gesture-only proxy dispatch, if view-dispatch already started a gesture,
proxy dispatch is ignored. Otherwise view-dispatch is restricted to non-gesture
dispatching only (and proxy-dispatch is already restricted to gesture only).
Bug: 158130948
Change-Id: Ied351663e16beda5acf49a52bdefea881c18b9cf
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 11fee2f..32b1c58 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -36,8 +36,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
-import java.util.function.Predicate;
-
/**
* Input consumer for handling touch on the recents/Launcher activity.
*/
@@ -50,8 +48,6 @@
private final InputMonitorCompat mInputMonitor;
private final int[] mLocationOnScreen = new int[2];
- private final boolean mProxyTouch;
- private final Predicate<MotionEvent> mEventReceiver;
private final boolean mStartingInActivityBounds;
private boolean mTargetHandledTouch;
@@ -64,15 +60,7 @@
mActivityInterface = gestureState.getActivityInterface();
mTarget = activity.getDragLayer();
- if (startingInActivityBounds) {
- mEventReceiver = mTarget::dispatchTouchEvent;
- mProxyTouch = true;
- } else {
- // Only proxy touches to controllers if we are starting touch from nav bar.
- mEventReceiver = mTarget::proxyTouchEvent;
- mTarget.getLocationOnScreen(mLocationOnScreen);
- mProxyTouch = mTarget.prepareProxyEventStarting();
- }
+ mTarget.getLocationOnScreen(mLocationOnScreen);
}
@Override
@@ -87,10 +75,6 @@
@Override
public void onMotionEvent(MotionEvent ev) {
- if (!mProxyTouch) {
- return;
- }
-
int flags = ev.getEdgeFlags();
if (!mStartingInActivityBounds) {
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
@@ -99,7 +83,7 @@
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
}
- boolean handled = mEventReceiver.test(ev);
+ boolean handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
ev.setEdgeFlags(flags);
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index f54edc2..b010b4b 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -90,13 +90,23 @@
}
};
- // Touch is being dispatched through the normal view dispatch system
- private static final int TOUCH_DISPATCHING_VIEW = 1 << 0;
+ // Touch coming from normal view system is being dispatched.
+ private static final int TOUCH_DISPATCHING_FROM_VIEW = 1 << 0;
// Touch is being dispatched through the normal view dispatch system, and started at the
- // system gesture region
- private static final int TOUCH_DISPATCHING_GESTURE = 1 << 1;
- // Touch is being dispatched through a proxy from InputMonitor
- private static final int TOUCH_DISPATCHING_PROXY = 1 << 2;
+ // system gesture region. In this case we prevent internal gesture handling and only allow
+ // normal view event handling.
+ private static final int TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION = 1 << 1;
+ // Touch coming from InputMonitor proxy is being dispatched 'only to gestures'. Note that both
+ // this and view-system can be active at the same time where view-system would go to the views,
+ // and this would go to the gestures.
+ // Note that this is not set when events are coming from proxy, but going through full dispatch
+ // process (both views and gestures) to allow view-system to easily take over in case it
+ // comes later.
+ private static final int TOUCH_DISPATCHING_FROM_PROXY = 1 << 2;
+ // ACTION_DOWN has been dispatched to child views and ACTION_UP or ACTION_CANCEL is pending.
+ // Note that the event source can either be view-dispatching or proxy-dispatching based on if
+ // TOUCH_DISPATCHING_VIEW is present or not.
+ private static final int TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS = 1 << 3;
protected final float[] mTmpXY = new float[2];
protected final float[] mTmpRectPoints = new float[4];
@@ -204,7 +214,8 @@
protected boolean findActiveController(MotionEvent ev) {
mActiveController = null;
- if ((mTouchDispatchState & (TOUCH_DISPATCHING_GESTURE | TOUCH_DISPATCHING_PROXY)) == 0) {
+ if ((mTouchDispatchState & (TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION
+ | TOUCH_DISPATCHING_FROM_PROXY)) == 0) {
// Only look for controllers if we are not dispatching from gesture area and proxy is
// not active
mActiveController = findControllerToHandleTouch(ev);
@@ -283,19 +294,28 @@
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case ACTION_DOWN: {
- mTouchDispatchState |= TOUCH_DISPATCHING_VIEW;
+ if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
+ // Cancel the previous touch
+ int action = ev.getAction();
+ ev.setAction(ACTION_CANCEL);
+ super.dispatchTouchEvent(ev);
+ ev.setAction(action);
+ }
+ mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW
+ | TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
if (isEventInLauncher(ev)) {
- mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
} else {
- mTouchDispatchState |= TOUCH_DISPATCHING_GESTURE;
+ mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
}
break;
}
case ACTION_CANCEL:
case ACTION_UP:
- mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
- mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
break;
}
super.dispatchTouchEvent(ev);
@@ -305,43 +325,53 @@
}
/**
- * Called before we are about to receive proxy events.
- *
- * @return false if we can't handle proxy at this time
- */
- public boolean prepareProxyEventStarting() {
- mProxyTouchController = null;
- if ((mTouchDispatchState & TOUCH_DISPATCHING_VIEW) != 0 && mActiveController != null) {
- // We are already dispatching using view system and have an active controller, we can't
- // handle another controller.
-
- // This flag was already cleared in proxy ACTION_UP or ACTION_CANCEL. Added here just
- // to be safe
- mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
- return false;
- }
-
- mTouchDispatchState |= TOUCH_DISPATCHING_PROXY;
- return true;
- }
-
- /**
* Proxies the touch events to the gesture handlers
*/
- public boolean proxyTouchEvent(MotionEvent ev) {
- boolean handled;
- if (mProxyTouchController != null) {
- handled = mProxyTouchController.onControllerTouchEvent(ev);
+ public boolean proxyTouchEvent(MotionEvent ev, boolean allowViewDispatch) {
+ int actionMasked = ev.getActionMasked();
+ boolean isViewDispatching = (mTouchDispatchState & TOUCH_DISPATCHING_FROM_VIEW) != 0;
+
+ // Only do view dispatch if another view-dispatching is not running, or we already started
+ // proxy-dispatching before. Note that view-dispatching can always take over the proxy
+ // dispatching at anytime, but not vice-versa.
+ allowViewDispatch = allowViewDispatch && !isViewDispatching
+ && (actionMasked == ACTION_DOWN
+ || ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0));
+
+ if (allowViewDispatch) {
+ mTouchDispatchState |= TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
+ super.dispatchTouchEvent(ev);
+
+ if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) {
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
+ }
+ return true;
} else {
- mProxyTouchController = findControllerToHandleTouch(ev);
- handled = mProxyTouchController != null;
+ boolean handled;
+ if (mProxyTouchController != null) {
+ handled = mProxyTouchController.onControllerTouchEvent(ev);
+ } else {
+ if (actionMasked == ACTION_DOWN) {
+ if (isViewDispatching && mActiveController != null) {
+ // A controller is already active, we can't initiate our own controller
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
+ } else {
+ // We will control the handler via proxy
+ mTouchDispatchState |= TOUCH_DISPATCHING_FROM_PROXY;
+ }
+ }
+ if ((mTouchDispatchState & TOUCH_DISPATCHING_FROM_PROXY) != 0) {
+ mProxyTouchController = findControllerToHandleTouch(ev);
+ }
+ handled = mProxyTouchController != null;
+ }
+ if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) {
+ mProxyTouchController = null;
+ mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
+ }
+ return handled;
}
- int action = ev.getAction();
- if (action == ACTION_UP || action == ACTION_CANCEL) {
- mProxyTouchController = null;
- mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
- }
- return handled;
}
/**