Do not perform invisible transitions while the screen is off.

This change caches whether launcher was active at the time of the screen
off, and assumes this last state when the screen is actually off.

While trying to understand the code, I renamed a couple class-internal
methods and flags, plus added comments. If they are not accurate, its
due to a misunderstanding on my part, and I will gladly revisit and
check whether all the assumptions I made still hold.

Bug: 261418621
Test: manually

Change-Id: I2ad25caf478100781a063c356c5fd2d20d3e1917
Merged-In: I2ad25caf478100781a063c356c5fd2d20d3e1917
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 95fea3e..e03c24d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -84,7 +84,6 @@
             };
 
     // Initialized in init.
-    private TaskbarKeyguardController mKeyguardController;
     private final TaskbarLauncherStateController
             mTaskbarLauncherStateController = new TaskbarLauncherStateController();
 
@@ -99,11 +98,12 @@
         mTaskbarLauncherStateController.init(mControllers, mLauncher);
 
         mLauncher.setTaskbarUIController(this);
-        mKeyguardController = taskbarControllers.taskbarKeyguardController;
 
         onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
 
         onStashedInAppChanged(mLauncher.getDeviceProfile());
+        mTaskbarLauncherStateController.onChangeScreenState(
+                mControllers.getSharedState().sysuiStateFlags, true /* fromInit */);
         mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
     }
 
@@ -121,7 +121,7 @@
     @Override
     protected boolean isTaskbarTouchable() {
         return !(mTaskbarLauncherStateController.isAnimatingToLauncher()
-                && mTaskbarLauncherStateController.goingToAlignedLauncherState());
+                && mTaskbarLauncherStateController.isTaskbarAlignedWithHotseat());
     }
 
     public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) {
@@ -169,15 +169,6 @@
     @Nullable
     private Animator onLauncherResumedOrPaused(
             boolean isResumed, boolean fromInit, boolean startAnimation, int duration) {
-        if (mKeyguardController.isScreenOff()) {
-            if (!isResumed) {
-                return null;
-            } else {
-                // Resuming implicitly means device unlocked
-                mKeyguardController.setScreenOn();
-            }
-        }
-
         if (ENABLE_SHELL_TRANSITIONS && isResumed
                 && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
             // Launcher is resumed, but in a state where taskbar is still independent, so
@@ -329,6 +320,11 @@
     }
 
     @Override
+    public void onChangeScreenState(int screenState) {
+        mTaskbarLauncherStateController.onChangeScreenState(screenState, false /* fromInit */);
+    }
+
+    @Override
     public boolean isIconAlignedWithHotseat() {
         return mTaskbarLauncherStateController.isIconAlignedWithHotseat();
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 62713ca..a14931e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
 
 import android.animation.AnimatorSet;
@@ -56,7 +57,6 @@
 import android.view.RoundedCorner;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
@@ -578,6 +578,9 @@
         mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
         mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
                 (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
+
+        mControllers.uiController.onChangeScreenState(
+                systemUiStateFlags & SYSUI_STATE_SCREEN_STATE_MASK);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 931d79f..e00c45c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -209,7 +209,6 @@
         uiController.onDestroy();
         rotationButtonController.onDestroy();
         taskbarDragLayerController.onDestroy();
-        taskbarKeyguardController.onDestroy();
         taskbarUnfoldAnimationController.onDestroy();
         taskbarViewController.onDestroy();
         stashedHandleViewController.onDestroy();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index 93ba4eb..4e390f1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -1,19 +1,20 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 
 import android.app.KeyguardManager;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.util.ScreenOnTracker;
-import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
 import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
@@ -23,36 +24,35 @@
  */
 public class TaskbarKeyguardController implements TaskbarControllers.LoggableTaskbarController {
 
-    private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING |
-            SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING |
-            SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED |
-            SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+    private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING
+            | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING
+            | SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED
+            | SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
+            | SYSUI_STATE_SCREEN_STATE_MASK;
 
-    private final ScreenOnListener mScreenOnListener;
     private final TaskbarActivityContext mContext;
     private int mKeyguardSysuiFlags;
     private boolean mBouncerShowing;
     private NavbarButtonsViewController mNavbarButtonsViewController;
     private final KeyguardManager mKeyguardManager;
-    private boolean mIsScreenOff;
 
     public TaskbarKeyguardController(TaskbarActivityContext context) {
         mContext = context;
-        mScreenOnListener = isOn -> {
-            if (!isOn) {
-                mIsScreenOff = true;
-                AbstractFloatingView.closeOpenViews(mContext, false, TYPE_ALL);
-            }
-        };
         mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
     }
 
     public void init(NavbarButtonsViewController navbarButtonUIController) {
         mNavbarButtonsViewController = navbarButtonUIController;
-        ScreenOnTracker.INSTANCE.get(mContext).addListener(mScreenOnListener);
     }
 
     public void updateStateForSysuiFlags(int systemUiStateFlags) {
+        int interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
+        if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
+            // No change in keyguard relevant flags
+            return;
+        }
+        mKeyguardSysuiFlags = interestingKeyguardFlags;
+
         boolean bouncerShowing = (systemUiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0;
         boolean keyguardShowing = (systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING)
                 != 0;
@@ -60,11 +60,6 @@
                 (systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0;
         boolean dozing = (systemUiStateFlags & SYSUI_STATE_DEVICE_DOZING) != 0;
 
-        int interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
-        if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
-            return;
-        }
-        mKeyguardSysuiFlags = interestingKeyguardFlags;
 
         mBouncerShowing = bouncerShowing;
 
@@ -72,19 +67,17 @@
                 keyguardOccluded);
         updateIconsForBouncer();
 
-        if (keyguardShowing) {
-            AbstractFloatingView.closeOpenViews(mContext, true, TYPE_ALL);
+        boolean screenOffOrTransitioningOff = (systemUiStateFlags & SYSUI_STATE_SCREEN_ON) == 0;
+        boolean closeFloatingViews = keyguardShowing || screenOffOrTransitioningOff;
+
+        if (closeFloatingViews) {
+            // animate the closing of the views, unless the screen is already fully turned off.
+            boolean animateViewClosing =
+                    (systemUiStateFlags & SYSUI_STATE_SCREEN_STATE_MASK) != SCREEN_STATE_OFF;
+            AbstractFloatingView.closeOpenViews(mContext, animateViewClosing, TYPE_ALL);
         }
     }
 
-    public boolean isScreenOff() {
-        return mIsScreenOff;
-    }
-
-    public void setScreenOn() {
-        mIsScreenOff = false;
-    }
-
     /**
      * Hides/shows taskbar when keyguard is up
      */
@@ -95,9 +88,6 @@
         mNavbarButtonsViewController.setBackForBouncer(showBackForBouncer);
     }
 
-    public void onDestroy() {
-        ScreenOnTracker.INSTANCE.get(mContext).removeListener(mScreenOnListener);
-    }
 
     @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
@@ -106,6 +96,5 @@
         pw.println(prefix + "\tmKeyguardSysuiFlags=" + QuickStepContract.getSystemUiStateString(
                 mKeyguardSysuiFlags));
         pw.println(prefix + "\tmBouncerShowing=" + mBouncerShowing);
-        pw.println(prefix + "\tmIsScreenOff=" + mIsScreenOff);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 7d5a400..93a0c11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -18,7 +18,10 @@
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
+import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
 import static com.android.systemui.animation.Interpolators.EMPHASIZED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -53,16 +56,43 @@
  * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
  * the task bar accordingly.
  */
- public class TaskbarLauncherStateController {
+public class TaskbarLauncherStateController {
 
     private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    /** Launcher activity is resumed and focused. */
     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_RUNNING = 1 << 2;
 
-    private static final int FLAGS_LAUNCHER = FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING;
+    /**
+     * A external transition / animation is running that will result in FLAG_RESUMED being set.
+     **/
+    public static final int FLAG_TRANSITION_TO_RESUMED = 1 << 1;
+
+    /**
+     * Set while the launcher state machine is performing a state transition, see {@link
+     * StateManager.StateListener}.
+     */
+    public static final int FLAG_LAUNCHER_IN_STATE_TRANSITION = 1 << 2;
+
+    /**
+     * Whether the screen is currently on, or is transitioning to be on.
+     *
+     * This is cleared as soon as the screen begins to transition off.
+     */
+    private static final int FLAG_SCREEN_ON = 1 << 3;
+
+    /**
+     * Captures whether the launcher was active at the time the FLAG_SCREEN_ON was cleared.
+     * Always cleared when FLAG_SCREEN_ON is set.
+     * <p>
+     * FLAG_RESUMED will be cleared when the screen is off, since all apps get paused at this point.
+     * Thus, this flag indicates whether the launcher will be shown when the screen gets turned on
+     * again.
+     */
+    private static final int FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF = 1 << 4;
+
+    private static final int FLAGS_LAUNCHER_ACTIVE = FLAG_RESUMED | FLAG_TRANSITION_TO_RESUMED;
     /** Equivalent to an int with all 1s for binary operation purposes */
     private static final int FLAGS_ALL = ~0;
 
@@ -115,12 +145,13 @@
                 @Override
                 public void onStateTransitionStart(LauncherState toState) {
                     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;
+                        // Treat FLAG_LAUNCHER_IN_STATE_TRANSITION as a changed flag even if a
+                        // previous state transition was already running, so we update the new
+                        // target.
+                        mPrevState &= ~FLAG_LAUNCHER_IN_STATE_TRANSITION;
                         mLauncherState = toState;
                     }
-                    updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
+                    updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
                     if (!mShouldDelayLauncherStateAnim) {
                         if (toState == LauncherState.NORMAL) {
                             applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
@@ -133,7 +164,7 @@
                 @Override
                 public void onStateTransitionComplete(LauncherState finalState) {
                     mLauncherState = finalState;
-                    updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
+                    updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
                     applyState();
                     boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
                     com.android.launcher3.taskbar.Utilities.setOverviewDragState(
@@ -159,9 +190,6 @@
         resetIconAlignment();
 
         mLauncher.getStateManager().addStateListener(mStateListener);
-
-        // Initialize to the current launcher state
-        updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
         mLauncherState = launcher.getStateManager().getState();
         applyState(0);
 
@@ -182,6 +210,12 @@
         mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
     }
 
+    /**
+     * Creates a transition animation to the launcher activity.
+     *
+     * Warning: the resulting animation must be played, since this method has side effects on this
+     * controller's state.
+     */
     public Animator createAnimToLauncher(@NonNull LauncherState toState,
             @NonNull RecentsAnimationCallbacks callbacks, long duration) {
         // If going to overview, stash the task bar
@@ -197,7 +231,7 @@
         }
         stashController.updateStateForFlag(FLAG_IN_APP, false);
 
-        updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
+        updateStateForFlag(FLAG_TRANSITION_TO_RESUMED, true);
         animatorSet.play(stashController.createApplyStateAnimator(duration));
         animatorSet.play(applyState(duration, false));
 
@@ -225,12 +259,30 @@
         mShouldDelayLauncherStateAnim = shouldDelayLauncherStateAnim;
     }
 
+    /** Screen state changed, see QuickStepContract.SCREEN_STATE_* values. */
+    public void onChangeScreenState(int screenState, boolean fromInit) {
+        final boolean prevScreenIsOn = hasAnyFlag(FLAG_SCREEN_ON);
+        final boolean currScreenIsOn = hasAnyFlag(screenState, SYSUI_STATE_SCREEN_ON);
+
+        if (prevScreenIsOn == currScreenIsOn) return;
+
+        updateStateForFlag(FLAG_SCREEN_ON, currScreenIsOn);
+        updateStateForFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
+                prevScreenIsOn && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
+
+        if (fromInit) {
+            applyState(0);
+        } else {
+            applyState();
+        }
+    }
+
     /**
      * Updates the proper flag to change the state of the task bar.
      *
      * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
      *
-     * @param flag The flag to update.
+     * @param flag    The flag to update.
      * @param enabled Whether to enable the flag
      */
     public void updateStateForFlag(int flag, boolean enabled) {
@@ -269,6 +321,19 @@
         if (mPrevState == null || mPrevState != mState) {
             // If this is our initial state, treat all flags as changed.
             int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState;
+
+            if (DEBUG) {
+                String stateString;
+                if (mPrevState == null) {
+                    stateString = getStateString(mState) + "(initial update)";
+                } else {
+                    stateString = formatFlagChange(mState, mPrevState,
+                            TaskbarLauncherStateController::getStateString);
+                }
+                Log.d(TAG, "applyState: " + stateString
+                        + ", duration: " + duration
+                        + ", start: " + start);
+            }
             mPrevState = mState;
             animator = onStateChangeApplied(changedFlags, duration, start);
         }
@@ -276,26 +341,23 @@
     }
 
     private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
-        final boolean goingToLauncher = isInLauncher();
+        final boolean isInLauncher = isInLauncher();
         final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
         final float toAlignment = isIconAlignedWithHotseat ? 1 : 0;
         boolean handleOpenFloatingViews = false;
         if (DEBUG) {
-            Log.d(TAG, "onStateChangeApplied - mState: " + getStateString(mState)
-                    + ", changedFlags: " + getStateString(changedFlags)
-                    + ", goingToLauncher: " + goingToLauncher
+            Log.d(TAG, "onStateChangeApplied - isInLauncher: " + isInLauncher
                     + ", mLauncherState: " + mLauncherState
                     + ", toAlignment: " + toAlignment);
         }
         AnimatorSet animatorSet = new AnimatorSet();
 
-        // Add the state animation first to ensure FLAG_IN_STASHED_LAUNCHER_STATE is set and we can
-        // determine whether goingToUnstashedLauncherStateChanged.
-        if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
-            boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
-            playStateTransitionAnim(animatorSet, duration, committed);
+        if (hasAnyFlag(changedFlags, FLAG_LAUNCHER_IN_STATE_TRANSITION)) {
+            boolean launcherTransitionCompleted = !hasAnyFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION);
+            playStateTransitionAnim(animatorSet, duration, launcherTransitionCompleted);
 
-            if (committed && mLauncherState == LauncherState.QUICK_SWITCH_FROM_HOME) {
+            if (launcherTransitionCompleted
+                    && mLauncherState == LauncherState.QUICK_SWITCH_FROM_HOME) {
                 // We're about to be paused, set immediately to ensure seamless handoff.
                 updateStateForFlag(FLAG_RESUMED, false);
                 applyState(0 /* duration */);
@@ -306,37 +368,37 @@
             }
         }
 
-        if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER)) {
+        if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER_ACTIVE)) {
             animatorSet.addListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationEnd(Animator animation) {
-                    mIsAnimatingToLauncher = false;
-                }
-
-                @Override
                 public void onAnimationStart(Animator animation) {
-                    mIsAnimatingToLauncher = goingToLauncher;
+                    mIsAnimatingToLauncher = isInLauncher;
 
                     TaskbarStashController stashController =
                             mControllers.taskbarStashController;
                     if (DEBUG) {
-                        Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !goingToLauncher);
+                        Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !isInLauncher);
                     }
-                    stashController.updateStateForFlag(FLAG_IN_APP, !goingToLauncher);
+                    stashController.updateStateForFlag(FLAG_IN_APP, !isInLauncher);
                     stashController.applyState(duration);
                 }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mIsAnimatingToLauncher = false;
+                }
             });
 
             // Handle closing open popups when going home/overview
             handleOpenFloatingViews = true;
         }
-        if (handleOpenFloatingViews && goingToLauncher) {
+
+        if (handleOpenFloatingViews && isInLauncher) {
             AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext);
         }
 
-        float backgroundAlpha =
-                goingToLauncher && mLauncherState.isTaskbarAlignedWithHotseat(mLauncher)
-                        ? 0 : 1;
+        float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
+
         // Don't animate if background has reached desired value.
         if (mTaskbarBackgroundAlpha.isAnimating()
                 || mTaskbarBackgroundAlpha.value != backgroundAlpha) {
@@ -347,21 +409,20 @@
                         + " -> " + backgroundAlpha + ": " + duration);
             }
 
-            boolean goingToLauncherIconNotAligned = goingToLauncher && !isIconAlignedWithHotseat;
-            boolean notGoingToLauncherIconNotAligned = !goingToLauncher
-                    && !isIconAlignedWithHotseat;
-            boolean goingToLauncherIconIsAligned = goingToLauncher && isIconAlignedWithHotseat;
+            boolean isInLauncherIconNotAligned = isInLauncher && !isIconAlignedWithHotseat;
+            boolean notInLauncherIconNotAligned = !isInLauncher && !isIconAlignedWithHotseat;
+            boolean isInLauncherIconIsAligned = isInLauncher && isIconAlignedWithHotseat;
 
             float startDelay = 0;
             // We want to delay the background from fading in so that the icons have time to move
             // into the bounds of the background before it appears.
-            if (goingToLauncherIconNotAligned) {
+            if (isInLauncherIconNotAligned) {
                 startDelay = duration * TASKBAR_BG_ALPHA_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
-            } else if (notGoingToLauncherIconNotAligned) {
+            } else if (notInLauncherIconNotAligned) {
                 startDelay = duration * TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
             }
             float newDuration = duration - startDelay;
-            if (goingToLauncherIconIsAligned) {
+            if (isInLauncherIconIsAligned) {
                 // Make the background fade out faster so that it is gone by the time the
                 // icons move outside of the bounds of the background.
                 newDuration = duration * TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT;
@@ -373,7 +434,8 @@
             animatorSet.play(taskbarBackgroundAlpha);
         }
 
-        float cornerRoundness = goingToLauncher ? 0 : 1;
+        float cornerRoundness = isInLauncher ? 0 : 1;
+
         // Don't animate if corner roundness has reached desired value.
         if (mTaskbarCornerRoundness.isAnimating()
                 || mTaskbarCornerRoundness.value != cornerRoundness) {
@@ -412,8 +474,12 @@
         return animatorSet;
     }
 
-    /** Returns whether we're going to a state where taskbar icons should align with launcher. */
-    public boolean goingToAlignedLauncherState() {
+    /**
+     * Whether the taskbar is aligned with the hotseat in the current/target launcher state.
+     *
+     * This refers to the intended state - a transition to this state might be in progress.
+     */
+    public boolean isTaskbarAlignedWithHotseat() {
         return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
     }
 
@@ -481,8 +547,13 @@
         }
     }
 
+    /** Whether the launcher is considered active. */
     private boolean isInLauncher() {
-        return (mState & FLAGS_LAUNCHER) != 0;
+        if (hasAnyFlag(FLAG_SCREEN_ON)) {
+            return hasAnyFlag(FLAGS_LAUNCHER_ACTIVE);
+        } else {
+            return hasAnyFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF);
+        }
     }
 
     /**
@@ -509,7 +580,8 @@
         if (firstFrameVisChanged && mCanSyncViews && !Utilities.isRunningInTestHarness()) {
             ViewRootSync.synchronizeNextDraw(mLauncher.getHotseat(),
                     mControllers.taskbarActivityContext.getDragLayer(),
-                    () -> {});
+                    () -> {
+                    });
         }
     }
 
@@ -562,7 +634,7 @@
 
             // Update the resumed state immediately to ensure a seamless handoff
             boolean launcherResumed = !finishedToApp;
-            updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+            updateStateForFlag(FLAG_TRANSITION_TO_RESUMED, false);
             updateStateForFlag(FLAG_RESUMED, launcherResumed);
             applyState();
 
@@ -576,17 +648,15 @@
     }
 
     private static String getStateString(int flags) {
-        StringJoiner str = new StringJoiner("|");
-        if ((flags & FLAG_RESUMED) != 0) {
-            str.add("FLAG_RESUMED");
-        }
-        if ((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0) {
-            str.add("FLAG_RECENTS_ANIMATION_RUNNING");
-        }
-        if ((flags & FLAG_TRANSITION_STATE_RUNNING) != 0) {
-            str.add("FLAG_TRANSITION_STATE_RUNNING");
-        }
-        return str.toString();
+        StringJoiner result = new StringJoiner("|");
+        appendFlag(result, flags, FLAG_RESUMED, "resumed");
+        appendFlag(result, flags, FLAG_TRANSITION_TO_RESUMED, "transition_to_resumed");
+        appendFlag(result, flags, FLAG_LAUNCHER_IN_STATE_TRANSITION,
+                "launcher_in_state_transition");
+        appendFlag(result, flags, FLAG_SCREEN_ON, "screen_on");
+        appendFlag(result, flags, FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
+                "launcher_active_at_screen_off");
+        return result.toString();
     }
 
     protected void dumpLogs(String prefix, PrintWriter pw) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index cbc1672..43a11fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -81,7 +81,7 @@
 
     public static final int FLAG_IN_APP = 1 << 0;
     public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted
-    public static final int FLAG_STASHED_IN_SYSUI_STATE = 1 << 2; // app pinning, keyguard, etc.
+    public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 2; // shade open, ...
     public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 3; // setup wizard and AllSetActivity
     public static final int FLAG_STASHED_IN_APP_IME = 1 << 4; // IME is visible
     public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
@@ -89,13 +89,14 @@
     public static final int FLAG_IN_SETUP = 1 << 7; // In the Setup Wizard
     public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 8; // phone screen gesture nav, stashed
     public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 9; // Autohide (transient taskbar).
+    public static final int FLAG_STASHED_SYSUI = 1 << 10; //  app pinning, keyguard, etc.
 
     // If any of these flags are enabled, isInApp should return true.
     private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
 
     // If we're in an app and any of these flags are enabled, taskbar should be stashed.
     private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
-            | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_SETUP
+            | FLAG_STASHED_IN_APP_SYSUI | FLAG_STASHED_IN_APP_SETUP
             | FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS
             | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
 
@@ -218,11 +219,11 @@
                 boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
                 boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
                 boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
-                boolean stashedInTaskbarAllApps =
-                        hasAnyFlag(flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS);
-                boolean stashedForSmallScreen = hasAnyFlag(flags, FLAG_STASHED_SMALL_SCREEN);
-                return (inApp && stashedInApp) || (!inApp && stashedLauncherState)
-                        || stashedInTaskbarAllApps || stashedForSmallScreen;
+                boolean forceStashed = hasAnyFlag(flags,
+                        FLAG_STASHED_SYSUI
+                                | FLAG_STASHED_IN_TASKBAR_ALL_APPS
+                                | FLAG_STASHED_SMALL_SCREEN);
+                return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed;
             });
 
     public TaskbarStashController(TaskbarActivityContext activity) {
@@ -898,13 +899,14 @@
         long animDuration = TASKBAR_STASH_DURATION;
         long startDelay = 0;
 
-        updateStateForFlag(FLAG_STASHED_IN_SYSUI_STATE, hasAnyFlag(systemUiStateFlags,
+        updateStateForFlag(FLAG_STASHED_IN_APP_SYSUI, hasAnyFlag(systemUiStateFlags,
+                SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+                        | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED));
+        updateStateForFlag(FLAG_STASHED_SYSUI, hasAnyFlag(systemUiStateFlags,
                 SYSUI_STATE_SCREEN_PINNING
                         | SYSUI_STATE_BOUNCER_SHOWING
                         | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
-                        | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
-                        | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
-                        | SYSUI_STATE_QUICK_SETTINGS_EXPANDED));
+                        | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED));
 
         // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
         mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
@@ -1068,13 +1070,14 @@
         StringJoiner sj = new StringJoiner("|");
         appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
-        appendFlag(sj, flags, FLAG_STASHED_IN_SYSUI_STATE, "FLAG_STASHED_IN_SYSUI_STATE");
+        appendFlag(sj, flags, FLAG_STASHED_IN_APP_SYSUI, "FLAG_STASHED_IN_APP_SYSUI");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
         appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
         appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS");
         appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO");
+        appendFlag(sj, flags, FLAG_STASHED_SYSUI, "FLAG_STASHED_SYSUI");
         return sj.toString();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 4c6d3fa..8046cd6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -125,6 +125,12 @@
     }
 
     /**
+     * Screen state changed, see QuickStepContract.SCREEN_STATE_* values.
+     */
+    public void onChangeScreenState(int screenState){
+    }
+
+    /**
      * Returns {@code true} iff taskbar is stashed.
      */
     public boolean isTaskbarStashed() {