Improve quick switch from home to taskbar

- Add LauncherState#isTaskbarAlignedWithHotseat() which defaults to !isTaskbarStashed(), but is always false for quick switch from home
- Replaced FLAG_TRANSITION_STATE_START_STASHED and FLAG_TRANSITION_STATE_COMMITTED_STASHED with FLAG_STATE_TRANSITION_RUNNING and a reference to mLauncherState. STATE_START is equivalent to TRANSITION_RUNNING changing to true, and STATE_COMMITTED is equivalent to TRANSITION_RUNNING changing to false. Then can get details from the state such as whether taskbar is stashed and icon alignment from mLauncherState

Test: quick switch from home, both with taskbar stashed in apps and not
Fixes: 194728611
Bug: 204657916
Change-Id: I6cf84ec73a4036e14cc7268667c6f62100884c27
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 76088ac..593bfd8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -49,8 +49,7 @@
 
     public static final int FLAG_RESUMED = 1 << 0;
     public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
-    public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2;
-    public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3;
+    public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2;
 
     /** Equivalent to an int with all 1s for binary operation purposes */
     private static final int FLAGS_ALL = ~0;
@@ -69,6 +68,7 @@
 
     private Integer mPrevState;
     private int mState;
+    private LauncherState mLauncherState = LauncherState.NORMAL;
 
     private boolean mIsAnimatingToLauncherViaGesture;
     private boolean mIsAnimatingToLauncherViaResume;
@@ -78,15 +78,20 @@
 
                 @Override
                 public void onStateTransitionStart(LauncherState toState) {
-                    updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
-                            toState.isTaskbarStashed());
+                    if (toState != mLauncherState) {
+                        // Treat FLAG_TRANSITION_STATE_RUNNING as a changed flag even if a previous
+                        // state transition was already running, so we update the new target.
+                        mPrevState &= ~FLAG_TRANSITION_STATE_RUNNING;
+                        mLauncherState = toState;
+                    }
+                    updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
                     applyState();
                 }
 
                 @Override
                 public void onStateTransitionComplete(LauncherState finalState) {
-                    updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED,
-                            finalState.isTaskbarStashed());
+                    mLauncherState = finalState;
+                    updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
                     applyState();
                 }
             };
@@ -127,7 +132,7 @@
         // Update stashed flags first to ensure goingToUnstashedLauncherState() returns correctly.
         TaskbarStashController stashController = mControllers.taskbarStashController;
         stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
-                toState.isTaskbarStashed());
+                toState.isTaskbarStashed(mLauncher));
         stashController.updateStateForFlag(FLAG_IN_APP, false);
 
         updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
@@ -189,8 +194,8 @@
         if (mPrevState == null || mPrevState != mState) {
             // If this is our initial state, treat all flags as changed.
             int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState;
-            animator = onStateChangeApplied(changedFlags, duration, start);
             mPrevState = mState;
+            animator = onStateChangeApplied(changedFlags, duration, start);
         }
         return animator;
     }
@@ -250,14 +255,15 @@
                     .setDuration(duration));
         }
 
-        if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) {
-            playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration,
-                    false /* committed */);
-        }
+        if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
+            boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
+            playStateTransitionAnim(animatorSet, duration, committed);
 
-        if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) {
-            playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration,
-                    true /* committed */);
+            if (committed && mLauncherState == LauncherState.QUICK_SWITCH) {
+                // We're about to be paused, set immediately to ensure seamless handoff.
+                updateStateForFlag(FLAG_RESUMED, false);
+                applyState(0 /* duration */);
+            }
         }
 
         if (start) {
@@ -271,17 +277,19 @@
         return !mControllers.taskbarStashController.isInStashedLauncherState();
     }
 
-    private void playStateTransitionAnim(boolean isTransitionStateStashed,
-            AnimatorSet animatorSet, long duration, boolean committed) {
+    private void playStateTransitionAnim(AnimatorSet animatorSet, long duration,
+            boolean committed) {
+        boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
+        float toAlignment = mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) ? 1 : 0;
+
         TaskbarStashController controller = mControllers.taskbarStashController;
-        controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
-                isTransitionStateStashed);
+        controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, isInStashedState);
         Animator stashAnimator = controller.applyStateWithoutStart(duration);
         if (stashAnimator != null) {
             stashAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (isTransitionStateStashed && committed) {
+                    if (isInStashedState && committed) {
                         // Reset hotseat alpha to default
                         mLauncher.getHotseat().setIconsAlpha(1);
                     }
@@ -295,10 +303,10 @@
                 }
             });
             animatorSet.play(stashAnimator);
-            animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
-                    getCurrentIconAlignmentRatioForLauncherState(),
-                    isTransitionStateStashed ? 0 : 1));
         }
+
+        animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
+                .setDuration(duration));
     }
 
     private boolean isResumed() {
@@ -309,14 +317,6 @@
         return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
     }
 
-    private boolean isTransitionStateStartStashed() {
-        return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0;
-    }
-
-    private boolean isTransitionStateCommittedStashed() {
-        return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0;
-    }
-
     private void onIconAlignmentRatioChangedForStateTransition() {
         if (!isResumed()) {
             return;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index c554fd0..8f89d30 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public boolean isTaskbarStashed() {
+    public boolean isTaskbarStashed(Launcher launcher) {
         return true;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index a4eff87..08d0a80 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -92,7 +92,7 @@
     }
 
     @Override
-    public boolean isTaskbarStashed() {
+    public boolean isTaskbarStashed(Launcher launcher) {
         return true;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index d36e76b..ffbb61b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
@@ -42,6 +43,10 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
+        DeviceProfile dp = launcher.getDeviceProfile();
+        if (dp.isTaskbarPresentInApps) {
+            return launcher.getColor(R.color.taskbar_background);
+        }
         return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
     }
 
@@ -55,4 +60,14 @@
     public int getVisibleElements(Launcher launcher) {
         return TASKBAR;
     }
+
+    @Override
+    public boolean isTaskbarStashed(Launcher launcher) {
+        return !launcher.getDeviceProfile().isTaskbarPresentInApps;
+    }
+
+    @Override
+    public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+        return false;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index ff3c517..f6148a7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -236,8 +236,10 @@
         //   - RecentsView fade (if it's empty)
         PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
         xAnim.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], LINEAR);
+        // Use QuickSwitchState instead of OverviewState to determine scrim color,
+        // since we need to take potential taskbar into account.
         xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
-                toState.getWorkspaceScrimColor(mLauncher), LINEAR);
+                QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR);
         if (mRecentsView.getTaskViewCount() == 0) {
             xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
         }
@@ -310,6 +312,11 @@
                 }
             });
             overviewAnim.start();
+
+            // Create an empty state transition so StateListeners get onStateTransitionStart().
+            mLauncher.getStateManager().createAnimationToNewWorkspace(
+                    OVERVIEW, config.duration, StateAnimationConfig.SKIP_ALL_ANIMATIONS)
+                    .dispatchOnStart();
             return;
         }
 
@@ -384,6 +391,7 @@
             config.animFlags = SKIP_ALL_ANIMATIONS;
             updateNonOverviewAnim(targetState, config);
             nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
+            mNonOverviewAnim.dispatchOnStart();
 
             new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start();
         } else {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2ad586d..ea3c796 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -629,7 +629,7 @@
      * this doesn't get adjusted to reflect the new child count after the taskView is dismissed/
      * removed from recentsView
      */
-    private int mSplitHiddenTaskViewIndex;
+    private int mSplitHiddenTaskViewIndex = -1;
     @Nullable
     private FloatingTaskView mFirstFloatingTaskView;
     @Nullable
@@ -3959,6 +3959,9 @@
 
     /** TODO(b/181707736) More gracefully handle exiting split selection state */
     private void resetFromSplitSelectionState() {
+        if (mSplitHiddenTaskViewIndex == -1) {
+            return;
+        }
         if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
             int pageToSnapTo = mCurrentPage;
             if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 15378e0..215b4ef 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -197,10 +197,16 @@
         return (getVisibleElements(launcher) & elements) == elements;
     }
 
-    public boolean isTaskbarStashed() {
+    /** Returns whether taskbar is stashed and thus should replace hotseat with a handle */
+    public boolean isTaskbarStashed(Launcher launcher) {
         return false;
     }
 
+    /** Returns whether taskbar is aligned with the hotseat vs position inside apps */
+    public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+        return !isTaskbarStashed(launcher);
+    }
+
     /**
      * Fraction shift in the vertical translation UI and related properties
      *