Fix some state issues with home and quick switch gestures

Handle the fact that LAUNCHER_STARTED can come 25ms+ later than LAUNCHER_PRESENT
- Don't call prepareRecentsUi() if we already completed the gesture to go home
  - Previously it was possible to get LAUNCHER_PRESENT -> GESTURE_STARTED ->
    GESTURE_COMPLETED -> LAUNCHER_STARTED. Because we go to BACKGROUND_APP state in
    LAUNCHER_STARTED, this sequence ended up there instead of home (b/124338231)
- Call setupRecentsViewUi() in LAUNCHER_PRESENT instead of LAUNCHER_START
  - Because setupRecentsViewUi() sets RecentsView to show the running task, it was
    interferring with quick switches that had the state sequence above

Other quick switch fixes
- Set canBeContinued = true for LAST_TASK gesture target. This handles cases like:
  switch from task 0 to task 1, intercept and go back to 0 (LAST_TASK), intercept
  again to go to 1
- Ignore deferred touch down target if we're continuing the previous gesture
- Set STATE_HANDLER_INVALIDATED as soon as we start finishing recents animation
  instead of waiting until the new task is launched. This is what we do when
  re-launching the last task, and it allows us to start a new gesture sooner.

One race condition still exists with consecutive quick switches: if you switch to
a new task, the next gesture might get stuck if it starts after finishing the
recents animation but before the task is fully launched/launcher is stopped.

Bug: 124338231
Bug: 111926330
Change-Id: Ia7e1eebe6e81e2f10bb42a10b2f46fd720da0dc1
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index 4792cc7..9506bfa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -130,7 +130,8 @@
         mVelocityTracker = VelocityTracker.obtain();
 
         mActivityControlHelper = activityControl;
-        mIsDeferredDownTarget = isDeferredDownTarget;
+        boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
+        mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
         mOverviewCallbacks = overviewCallbacks;
         mTaskOverlayFactory = taskOverlayFactory;
         mInputConsumer = inputConsumer;
@@ -142,8 +143,7 @@
 
         mDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
         mTouchSlop = NavigationBarCompat.getQuickStepTouchSlopPx();
-        // If active listener isn't null, we are continuing the previous gesture.
-        mPassedTouchSlop = mPassedDragSlop = mSwipeSharedState.getActiveListener() != null;
+        mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index efc228b..c2bbf5c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -162,8 +162,6 @@
     private static final int LAUNCHER_UI_STATES =
             STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
 
-    // For debugging, keep in sync with above states
-
     enum GestureEndTarget {
         HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE),
 
@@ -172,7 +170,7 @@
 
         NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP),
 
-        LAST_TASK(0, STATE_SCALED_CONTROLLER_LAST_TASK, false, false, ContainerType.APP);
+        LAST_TASK(0, STATE_SCALED_CONTROLLER_LAST_TASK, false, true, ContainerType.APP);
 
         GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued,
                 int containerType) {
@@ -234,6 +232,7 @@
     private ThumbnailData mTaskSnapshot;
 
     private MultiStateCallback mStateCallback;
+    // Used to control launcher components throughout the swipe gesture.
     private AnimatorPlaybackController mLauncherTransitionController;
 
     private T mActivity;
@@ -274,10 +273,8 @@
     private void initStateCallbacks() {
         mStateCallback = new MultiStateCallback(STATE_NAMES);
 
-        // Re-setup the recents UI when gesture starts, as the state could have been changed during
-        // that time by a previous window transition.
-        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_GESTURE_STARTED,
-                this::setupRecentsViewUi);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
+                this::onLauncherPresentAndGestureStarted);
 
         mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
                 this::initializeLauncherAnimationController);
@@ -285,9 +282,6 @@
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
                 this::launcherFrameDrawn);
 
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
-                this::notifyGestureStartedAsync);
-
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
                         | STATE_GESTURE_CANCELLED,
                 this::resetStateForAnimationCancel);
@@ -414,6 +408,8 @@
         } else {
             activity.setOnStartCallback(this::onLauncherStart);
         }
+
+        setupRecentsViewUi();
         return true;
     }
 
@@ -425,8 +421,12 @@
             return;
         }
 
-        mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
-                mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
+        // If we've already ended the gesture and are going home, don't prepare recents UI,
+        // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
+        if (mGestureEndTarget != HOME) {
+            mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
+                    mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
+        }
         AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
 
         if (mWasLauncherAlreadyVisible) {
@@ -450,11 +450,18 @@
             });
         }
 
-        setupRecentsViewUi();
         activity.getRootView().setOnApplyWindowInsetsListener(this);
         mStateCallback.setState(STATE_LAUNCHER_STARTED);
     }
 
+    private void onLauncherPresentAndGestureStarted() {
+        // Re-setup the recents UI when gesture starts, as the state could have been changed during
+        // that time by a previous window transition.
+        setupRecentsViewUi();
+
+        notifyGestureStartedAsync();
+    }
+
     private void setupRecentsViewUi() {
         if (mContinuingLastGesture) {
             return;
@@ -723,7 +730,7 @@
             final int lastTaskIndex = mRecentsView.getTaskViewCount() - 1;
             final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
             taskToLaunch = nextPage <= lastTaskIndex ? nextPage : lastTaskIndex;
-            goingToNewTask = mRecentsView != null && taskToLaunch != runningTaskIndex;
+            goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
         } else {
             goingToNewTask = false;
         }
@@ -859,8 +866,8 @@
             RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
         }
 
-        HomeAnimationFactory homeAnimFactory;
         if (mGestureEndTarget == HOME) {
+            HomeAnimationFactory homeAnimFactory;
             if (mActivity != null) {
                 homeAnimFactory = mActivityControlHelper.prepareHomeUI(mActivity);
             } else {
@@ -901,7 +908,6 @@
                 }
             });
             windowAnim.start();
-            homeAnimFactory = null;
         }
         // Always play the entire launcher animation when going home, since it is separate from
         // the animation that has been controlled thus far.
@@ -951,6 +957,7 @@
         }
 
         AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
+
         // We want the window alpha to be 0 once this threshold is met, so that the
         // FolderIconView can be seen morphing into the icon shape.
         final float windowAlphaThreshold = isFloatingIconView ? 0.75f : 1f;
@@ -1006,18 +1013,15 @@
         // Launch the task user scrolled to (mRecentsView.getNextPage()).
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             // We finish recents animation inside launchTask() when live tile is enabled.
-            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
-                    result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
-                    mMainThreadHandler);
+            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
         } else {
             mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
-                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
-                        result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
-                        mMainThreadHandler);
+                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
             });
         }
         TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
         doLogGesture(NEW_TASK);
+        reset();
     }
 
     public void reset() {