Support 4-finger gesture to quick switch
Fixes: 270610237
Test: 4-finger horizontal swipe -> quick switch
Change-Id: I981a7e93ecd07357c7a9cda075f476b397c448cc
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f1c4f68..80f5558 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -15,11 +15,15 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+
import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadFourFingerSwipe;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
@@ -106,6 +110,7 @@
newCancelListener(this::clearState);
private boolean mNoIntercept;
+ private Boolean mIsTrackpadFourFingerSwipe;
private LauncherState mStartState;
private boolean mIsHomeScreenVisible = true;
@@ -131,7 +136,9 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mIsTrackpadFourFingerSwipe = null;
mNoIntercept = !canInterceptTouch(ev);
if (mNoIntercept) {
return false;
@@ -140,6 +147,13 @@
// Only detect horizontal swipe for intercept, then we will allow swipe up as well.
mSwipeDetector.setDetectableScrollConditions(DIRECTION_RIGHT,
false /* ignoreSlopWhenSettling */);
+ } else if (isTrackpadMultiFingerSwipe(ev) && mIsTrackpadFourFingerSwipe == null
+ && action == ACTION_MOVE) {
+ mIsTrackpadFourFingerSwipe = isTrackpadFourFingerSwipe(ev);
+ mNoIntercept = !mIsTrackpadFourFingerSwipe;
+ if (mNoIntercept) {
+ return false;
+ }
}
if (mNoIntercept) {
@@ -162,9 +176,6 @@
if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
return false;
}
- if (isTrackpadMultiFingerSwipe(ev)) {
- return false;
- }
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
return false;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9795670..534eec1 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -2063,8 +2063,8 @@
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
- // Disable scrolling in RecentsView for trackpad gestures.
- if (!mGestureState.isTrackpadGesture()) {
+ // Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
+ if (!mGestureState.isThreeFingerTrackpadGesture()) {
mRecentsViewScrollLinked = true;
}
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 2b0623a..02f9f57 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -15,6 +15,9 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadFourFingerSwipe;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadThreeFingerSwipe;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
@@ -27,6 +30,7 @@
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
+import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import com.android.launcher3.statemanager.BaseState;
@@ -139,8 +143,30 @@
private final BaseActivityInterface mActivityInterface;
private final MultiStateCallback mStateCallback;
private final int mGestureId;
- private boolean mIsTrackpadGesture;
+ public enum TrackpadGestureType {
+ NONE,
+ // Assigned before we know whether it's a 3-finger or 4-finger gesture.
+ MULTI_FINGER,
+ THREE_FINGER,
+ FOUR_FINGER;
+
+ public static TrackpadGestureType getTrackpadGestureType(MotionEvent event) {
+ if (!isTrackpadMultiFingerSwipe(event)) {
+ return TrackpadGestureType.NONE;
+ }
+ if (isTrackpadThreeFingerSwipe(event)) {
+ return TrackpadGestureType.THREE_FINGER;
+ }
+ if (isTrackpadFourFingerSwipe(event)) {
+ return TrackpadGestureType.FOUR_FINGER;
+ }
+
+ return TrackpadGestureType.MULTI_FINGER;
+ }
+ }
+
+ private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
private CachedTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
private RemoteAnimationTarget mLastAppearedTaskTarget;
@@ -249,17 +275,22 @@
}
/**
- * Sets if the gesture is is from the trackpad.
+ * Sets if the gesture is is from the trackpad, if so, whether 3-finger, or 4-finger
*/
- public void setIsTrackpadGesture(boolean isTrackpadGesture) {
- mIsTrackpadGesture = isTrackpadGesture;
+ public void setTrackpadGestureType(TrackpadGestureType trackpadGestureType) {
+ mTrackpadGestureType = trackpadGestureType;
}
- /**
- * @return if the gesture is from the trackpad.
- */
public boolean isTrackpadGesture() {
- return mIsTrackpadGesture;
+ return mTrackpadGestureType != TrackpadGestureType.NONE;
+ }
+
+ public boolean isThreeFingerTrackpadGesture() {
+ return mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
+ }
+
+ public boolean isFourFingerTrackpadGesture() {
+ return mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER;
}
/**
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index fbe2778..07db194 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -249,7 +249,7 @@
}
GestureState gestureState = mService.createGestureState(GestureState.DEFAULT_STATE,
- false /* isTrackpadGesture */);
+ GestureState.TrackpadGestureType.NONE);
gestureState.setHandlingAtomicEvent(true);
AbsSwipeUpHandler interactionHandler = mService.getSwipeUpHandlerFactory()
.newHandler(gestureState, cmd.createTime);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 0531b47..038c674 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -24,11 +24,11 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
-import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
+import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
@@ -647,7 +647,7 @@
// onConsumerInactive and wipe the previous gesture state
GestureState prevGestureState = new GestureState(mGestureState);
GestureState newGestureState = createGestureState(mGestureState,
- isTrackpadMultiFingerSwipe(event));
+ getTrackpadGestureType(event));
newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis());
mConsumer.onConsumerAboutToBeSwitched();
mGestureState = newGestureState;
@@ -656,7 +656,7 @@
} else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
&& mDeviceState.canTriggerAssistantAction(event)) {
mGestureState = createGestureState(mGestureState,
- isTrackpadMultiFingerSwipe(event));
+ getTrackpadGestureType(event));
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
// should not interrupt it. QuickSwitch assumes that interruption can only
// happen if the next gesture is also quick switch.
@@ -713,9 +713,13 @@
event.setAction(ACTION_CANCEL);
}
- // Skip ACTION_POINTER_DOWN and ACTION_POINTER_UP events from trackpad.
- if (!mGestureState.isTrackpadGesture() || (action != ACTION_POINTER_DOWN
- && action != ACTION_POINTER_UP)) {
+ if (mGestureState.isTrackpadGesture() && (action == ACTION_POINTER_DOWN
+ || action == ACTION_POINTER_UP)) {
+ // Skip ACTION_POINTER_DOWN and ACTION_POINTER_UP events from trackpad.
+ if (action == ACTION_POINTER_DOWN) {
+ mGestureState.setTrackpadGestureType(getTrackpadGestureType(event));
+ }
+ } else {
mUncheckedConsumer.onMotionEvent(event);
}
@@ -749,7 +753,7 @@
}
public GestureState createGestureState(GestureState previousGestureState,
- boolean isTrackpadGesture) {
+ GestureState.TrackpadGestureType trackpadGestureType) {
final GestureState gestureState;
TopTaskTracker.CachedTaskInfo taskInfo;
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
@@ -766,7 +770,7 @@
taskInfo = TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false);
gestureState.updateRunningTask(taskInfo);
}
- gestureState.setIsTrackpadGesture(isTrackpadGesture);
+ gestureState.setTrackpadGestureType(trackpadGestureType);
// Log initial state for the gesture.
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current running task package name=")
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index a8963f6..2dcbbb9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -203,8 +203,24 @@
}
int edgeFlags = ev.getEdgeFlags();
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
- // Disable scrolling in RecentsView for trackpad gestures.
- if (!mGestureState.isTrackpadGesture()) {
+
+ if (mGestureState.isTrackpadGesture()) {
+ // Disable scrolling in RecentsView for 3-finger trackpad gesture. We don't know if a
+ // trackpad motion event is 3-finger or 4-finger with the U API until ACTION_MOVE (we
+ // skip ACTION_POINTER_UP events in TouchInteractionService), so in order to make sure
+ // that RecentsView always get a closed sequence of motion events and yet disable
+ // 3-finger scroll, we do the following (1) always dispatch ACTION_DOWN and ACTION_UP
+ // trackpad multi-finger motion events. (2) only dispatch 4-finger ACTION_MOVE motion
+ // events.
+ switch (ev.getActionMasked()) {
+ case ACTION_MOVE -> {
+ if (mGestureState.isFourFingerTrackpadGesture()) {
+ mRecentsViewDispatcher.dispatchEvent(ev);
+ }
+ }
+ default -> mRecentsViewDispatcher.dispatchEvent(ev);
+ }
+ } else {
mRecentsViewDispatcher.dispatchEvent(ev);
}
ev.setEdgeFlags(edgeFlags);
@@ -312,9 +328,12 @@
// Do not allow quick switch for trackpad 3-finger gestures
// TODO(b/261815244): might need to impose stronger conditions for the swipe
// angle
- boolean noQuickSwitchForTrackpadGesture = mGestureState.isTrackpadGesture()
- && isLikelyToStartNewTask;
- if (isHorizontalSwipeWhenDisabled || noQuickSwitchForTrackpadGesture) {
+ boolean noQuickSwitchForThreeFingerGesture = isLikelyToStartNewTask
+ && mGestureState.isThreeFingerTrackpadGesture();
+ boolean noQuickstepForFourFingerGesture = !isLikelyToStartNewTask
+ && mGestureState.isFourFingerTrackpadGesture();
+ if (isHorizontalSwipeWhenDisabled || noQuickSwitchForThreeFingerGesture
+ || noQuickstepForFourFingerGesture) {
forceCancelGesture(ev);
break;
}
diff --git a/src/com/android/launcher3/MotionEventsUtils.java b/src/com/android/launcher3/MotionEventsUtils.java
index 7f8794d..40de003 100644
--- a/src/com/android/launcher3/MotionEventsUtils.java
+++ b/src/com/android/launcher3/MotionEventsUtils.java
@@ -42,6 +42,14 @@
&& event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
}
+ public static boolean isTrackpadThreeFingerSwipe(MotionEvent event) {
+ return isTrackpadMultiFingerSwipe(event) && event.getPointerCount() == 3;
+ }
+
+ public static boolean isTrackpadFourFingerSwipe(MotionEvent event) {
+ return isTrackpadMultiFingerSwipe(event) && event.getPointerCount() == 4;
+ }
+
public static boolean isTrackpadMotionEvent(MotionEvent event) {
return isTrackpadScroll(event) || isTrackpadMultiFingerSwipe(event);
}