diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index a87e290521..e99dae360d 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -646,3 +646,13 @@ flag { description: "Enable more grid scale options on the launcher for desktop experience" bug: "375491272" } + +flag { + name: "enable_gesture_nav_horizontal_touch_slop" + namespace: "launcher" + description: "Enables horizontal touch slop checking in non-vertical fling navigation gestures" + bug: "394364217" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 23b8e365fd..0566f09104 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -31,6 +31,7 @@ import static com.android.launcher3.BaseActivity.EVENT_STARTED; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.Flags.enableAdditionalHomeAnimations; +import static com.android.launcher3.Flags.enableGestureNavHorizontalTouchSlop; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.Flags.msdlFeedback; import static com.android.launcher3.PagedView.INVALID_PAGE; @@ -1104,7 +1105,12 @@ public abstract class AbsSwipeUpHandler< public void onGestureCancelled() { updateDisplacement(0); mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); - handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */); + handleNormalGestureEnd( + /* endVelocityPxPerMs= */ 0, + /* isFling= */ false, + /* velocityPxPerMs= */ new PointF(), + /* isCancel= */ true, + /* horizontalTouchSlopPassed= */ false); } /** @@ -1113,7 +1119,8 @@ public abstract class AbsSwipeUpHandler< * @param velocityPxPerMs The x and y components of the velocity when the gesture ends. */ @UiThread - public void onGestureEnded(float endVelocityPxPerMs, PointF velocityPxPerMs) { + public void onGestureEnded( + float endVelocityPxPerMs, PointF velocityPxPerMs, boolean horizontalTouchSlopPassed) { float flingThreshold = mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_speed); boolean isFling = mGestureStarted && !mIsMotionPaused @@ -1126,7 +1133,11 @@ public abstract class AbsSwipeUpHandler< mLogDirectionUpOrLeft = velocityPxPerMs.x < 0; } Runnable handleNormalGestureEndCallback = () -> handleNormalGestureEnd( - endVelocityPxPerMs, isFling, velocityPxPerMs, /* isCancel= */ false); + endVelocityPxPerMs, + isFling, + velocityPxPerMs, + /* isCancel= */ false, + horizontalTouchSlopPassed); if (mRecentsView != null) { mRecentsView.runOnPageScrollsInitialized(handleNormalGestureEndCallback); } else { @@ -1259,7 +1270,11 @@ public abstract class AbsSwipeUpHandler< } private GestureEndTarget calculateEndTarget( - PointF velocityPxPerMs, float endVelocityPxPerMs, boolean isFlingY, boolean isCancel) { + PointF velocityPxPerMs, + float endVelocityPxPerMs, + boolean isFlingY, + boolean isCancel, + boolean horizontalTouchSlopPassed) { ActiveGestureProtoLogProxy.logOnCalculateEndTarget( dpiFromPx(velocityPxPerMs.x), dpiFromPx(velocityPxPerMs.y), @@ -1276,7 +1291,7 @@ public abstract class AbsSwipeUpHandler< } else if (isFlingY) { endTarget = calculateEndTargetForFlingY(velocityPxPerMs, endVelocityPxPerMs); } else { - endTarget = calculateEndTargetForNonFling(velocityPxPerMs); + endTarget = calculateEndTargetForNonFling(velocityPxPerMs, horizontalTouchSlopPassed); } if (mDeviceState.isOverviewDisabled() && endTarget == RECENTS) { @@ -1314,12 +1329,14 @@ public abstract class AbsSwipeUpHandler< return willGoToNewTask ? NEW_TASK : HOME; } - private GestureEndTarget calculateEndTargetForNonFling(PointF velocity) { + private GestureEndTarget calculateEndTargetForNonFling( + PointF velocity, boolean horizontalTouchSlopPassed) { final boolean isScrollingToNewTask = isScrollingToNewTask(); // Fully gestural mode. final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() - .getDimension(R.dimen.quickstep_fling_threshold_speed); + .getDimension(R.dimen.quickstep_fling_threshold_speed) + && (!enableGestureNavHorizontalTouchSlop() || horizontalTouchSlopPassed); if (isScrollingToNewTask && isFlingX) { // Flinging towards new task takes precedence over mIsMotionPaused (which only // checks y-velocity). @@ -1359,11 +1376,15 @@ public abstract class AbsSwipeUpHandler< @UiThread private void handleNormalGestureEnd( - float endVelocityPxPerMs, boolean isFling, PointF velocityPxPerMs, boolean isCancel) { + float endVelocityPxPerMs, + boolean isFling, + PointF velocityPxPerMs, + boolean isCancel, + boolean horizontalTouchSlopPassed) { long duration = MAX_SWIPE_DURATION; float currentShift = mCurrentShift.value; final GestureEndTarget endTarget = calculateEndTarget( - velocityPxPerMs, endVelocityPxPerMs, isFling, isCancel); + velocityPxPerMs, endVelocityPxPerMs, isFling, isCancel, horizontalTouchSlopPassed); // Set the state, but don't notify until the animation completes mGestureState.setEndTarget(endTarget, false /* isAtomic */); mAnimationFactory.setEndTarget(endTarget); diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index 6bd34008be..984f390721 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -435,7 +435,11 @@ constructor( logShowOverviewFrom(command.type) containerInterface.runOnInitBackgroundStateUI { Log.d(TAG, "recents animation started - onInitBackgroundStateUI: $command") - interactionHandler.onGestureEnded(0f, PointF()) + interactionHandler.onGestureEnded( + 0f, + PointF(), + /* horizontalTouchSlopPassed= */ false, + ) } command.removeListener(this) } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 5963a7ce88..7cae5b8336 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -483,7 +483,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC : velocityYPxPerMs; mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); mInteractionHandler.onGestureEnded(velocityPxPerMs, - new PointF(velocityXPxPerMs, velocityYPxPerMs)); + new PointF(velocityXPxPerMs, velocityYPxPerMs), + Math.abs(mDownPos.x - mLastPos.x) > mTouchSlop); } } else { // Since we start touch tracking on DOWN, we may reach this state without actually diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java index 0c7461028d..6fbbd597d0 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java @@ -364,7 +364,7 @@ public abstract class AbsSwipeUpHandlerTestCase< float xVelocityPxPerMs = isQuickSwitch ? 100 : 0; float yVelocityPxPerMs = isQuickSwitch ? 0 : -100; swipeHandler.onGestureEnded( - yVelocityPxPerMs, new PointF(xVelocityPxPerMs, yVelocityPxPerMs)); + yVelocityPxPerMs, new PointF(xVelocityPxPerMs, yVelocityPxPerMs), isQuickSwitch); swipeHandler.onCalculateEndTarget(); runOnMainSync(swipeHandler::onSettledOnEndTarget); diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt index 35f12181ab..5661dcf699 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt @@ -116,14 +116,14 @@ class LauncherSwipeHandlerV2Test { @Test fun goHomeFromAppByTrackpad_updateEduStats() { gestureState.setTrackpadGestureType(GestureState.TrackpadGestureType.THREE_FINGER) - underTest.onGestureEnded(flingSpeed, PointF()) + underTest.onGestureEnded(flingSpeed, PointF(), /* horizontalTouchSlopPassed= */ false) verify(systemUiProxy) .updateContextualEduStats(/* isTrackpadGesture= */ eq(true), eq(GestureType.HOME)) } @Test fun goHomeFromAppByTouch_updateEduStats() { - underTest.onGestureEnded(flingSpeed, PointF()) + underTest.onGestureEnded(flingSpeed, PointF(), /* horizontalTouchSlopPassed= */ false) verify(systemUiProxy) .updateContextualEduStats(/* isTrackpadGesture= */ eq(false), eq(GestureType.HOME)) }