Merge "Update BorderAnimator to work with layout updates" into udc-dev
diff --git a/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml b/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml
deleted file mode 100644
index 2ab6749..0000000
--- a/quickstep/res/drawable/redesigned_default_sandbox_app_icon.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <solid android:color="?attr/surfaceHome" />
-</shape>
diff --git a/quickstep/res/drawable/hotseat_icon_home.xml b/quickstep/res/drawable/redesigned_hotseat_icon.xml
similarity index 94%
rename from quickstep/res/drawable/hotseat_icon_home.xml
rename to quickstep/res/drawable/redesigned_hotseat_icon.xml
index 9ef4863..535756d 100644
--- a/quickstep/res/drawable/hotseat_icon_home.xml
+++ b/quickstep/res/drawable/redesigned_hotseat_icon.xml
@@ -16,6 +16,5 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/surfaceHome" />
     <corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
 </shape>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
index af86ae7..3b484dc 100644
--- a/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout-land/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -40,28 +40,28 @@
         android:id="@+id/hotseat_icon_1"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_2"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_3"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_4"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
index 983c15b..850f6e3 100644
--- a/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout-land/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
@@ -39,42 +39,42 @@
         android:id="@+id/hotseat_search_bar"
         android:layout_width="200dp"
         android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_1"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_2"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_3"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_4"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_5"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
index b41eb8d..821628a 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_foldable_mock_hotseat.xml
@@ -26,7 +26,7 @@
         android:id="@+id/hotseat_search_bar"
         android:layout_width="0dp"
         android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true"
 
         app:layout_constraintTop_toTopOf="parent"
@@ -50,35 +50,35 @@
         android:id="@+id/hotseat_icon_1"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_2"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_3"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_4"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_5"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index 6c4ca2e..7d5505e 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -96,15 +96,6 @@
         android:layout_height="match_parent"
         android:background="@drawable/gesture_tutorial_ripple" />
 
-    <include
-        android:id="@+id/gesture_tutorial_fake_taskbar_view"
-        layout="@layout/gesture_tutorial_tablet_mock_taskbar"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:layout_marginBottom="@dimen/gesture_tutorial_taskbar_margin_bottom" />
-
     <ImageView
         android:id="@+id/gesture_tutorial_edge_gesture_video"
         android:layout_width="match_parent"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
index e93a0fc..f5145ba 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -39,35 +39,36 @@
         android:id="@+id/hotseat_icon_1"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_2"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_3"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_4"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
+        android:id="@+id/hotseat_search_bar"
         android:layout_width="0dp"
         android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
         android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true"
 
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
index b41eb8d..821628a 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_tablet_mock_hotseat.xml
@@ -26,7 +26,7 @@
         android:id="@+id/hotseat_search_bar"
         android:layout_width="0dp"
         android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true"
 
         app:layout_constraintTop_toTopOf="parent"
@@ -50,35 +50,35 @@
         android:id="@+id/hotseat_icon_1"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_2"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_3"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_4"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
     <View
         android:id="@+id/hotseat_icon_5"
         android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
         android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
-        android:background="@drawable/hotseat_icon_home"
+        android:background="@drawable/redesigned_hotseat_icon"
         android:clipToOutline="true" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 1ceb653..8e1059b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -54,6 +54,10 @@
     // Initialized in init.
     private TaskbarControllers mControllers;
 
+    // Used to defer any UI updates during the SUW unstash animation.
+    private boolean mDeferUpdatesForSUW;
+    private Runnable mDeferredUpdates;
+
     public TaskbarModelCallbacks(
             TaskbarActivityContext context, TaskbarView container) {
         mContext = context;
@@ -194,10 +198,38 @@
         }
         hotseatItemInfos = mControllers.taskbarRecentAppsController
                 .updateHotseatItemInfos(hotseatItemInfos);
+
+        if (mDeferUpdatesForSUW) {
+            ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
+            mDeferredUpdates = () -> {
+                updateHotseatItemsAndBackground(finalHotseatItemInfos);
+            };
+        } else {
+            updateHotseatItemsAndBackground(hotseatItemInfos);
+        }
+    }
+
+    private void updateHotseatItemsAndBackground(ItemInfo[] hotseatItemInfos) {
         mContainer.updateHotseatItems(hotseatItemInfos);
         mControllers.taskbarViewController.updateIconsBackground();
     }
 
+    /**
+     * This is used to defer UI updates after SUW builds the unstash animation.
+     * @param defer if true, defers updates to the UI
+     *              if false, posts updates (if any) to the UI
+     */
+    public void setDeferUpdatesForSUW(boolean defer) {
+        mDeferUpdatesForSUW = defer;
+
+        if (!mDeferUpdatesForSUW) {
+            if (mDeferredUpdates != null) {
+                mContainer.post(mDeferredUpdates);
+                mDeferredUpdates = null;
+            }
+        }
+    }
+
     @Override
     public void onRunningTasksChanged() {
         updateRunningApps();
@@ -232,5 +264,7 @@
             pw.println(
                     String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size()));
         }
+        pw.println(String.format("%s\tmDeferUpdatesForSUW=%b", prefix, mDeferUpdatesForSUW));
+        pw.println(String.format("%s\tupdates pending=%b", prefix, (mDeferredUpdates != null)));
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 6f82c7d..00e14ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -585,10 +585,14 @@
      *                            actually be used since this animation tracks a swipe progress.
      */
     protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
+        // Defer any UI updates now to avoid the UI becoming stale when the animation plays.
+        mControllers.taskbarViewController.setDeferUpdatesForSUW(true);
         createAnimToIsStashed(
                 /* isStashed= */ false,
                 placeholderDuration,
                 TRANSITION_UNSTASH_SUW_MANUAL);
+        animation.addListener(AnimatorListeners.forEndCallback(
+                () -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false)));
         animation.play(mAnimator);
     }
 
@@ -804,7 +808,7 @@
         }
 
         mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
-                EMPHASIZED);
+                EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL);
 
         play(skippable, mControllers.stashedHandleViewController
                 .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 7429185..4abd995 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
 
+import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -286,7 +287,7 @@
     }
 
     private ValueAnimator createRevealAnimForView(View view, boolean isStashed, float newWidth,
-            boolean isQsb) {
+            boolean isQsb, boolean dispatchOnAnimationStart) {
         Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
         int centerY = viewBounds.centerY();
         int halfHandleHeight = mStashedHandleHeight / 2;
@@ -318,8 +319,24 @@
                 : 0f;
         float stashedRadius = stashedRect.height() / 2f;
 
-        return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
+        ValueAnimator reveal = new RoundedRectRevealOutlineProvider(radius,
+                stashedRadius, viewBounds, stashedRect)
                 .createRevealAnimator(view, !isStashed, 0);
+        // SUW animation does not dispatch animation start until *after* the animation is complete.
+        // In order to work properly, the reveal animation start needs to be called immediately.
+        if (dispatchOnAnimationStart) {
+            for (Animator.AnimatorListener listener : reveal.getListeners()) {
+                listener.onAnimationStart(reveal);
+            }
+        }
+        return reveal;
+    }
+
+    /**
+     * Defers any updates to the UI for the setup wizard animation.
+     */
+    public void setDeferUpdatesForSUW(boolean defer) {
+        mModelCallbacks.setDeferUpdatesForSUW(defer);
     }
 
     /**
@@ -332,7 +349,7 @@
      * @param interpolator The interpolator to use for all animations.
      */
     public void addRevealAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
-            Interpolator interpolator) {
+            Interpolator interpolator, boolean dispatchOnAnimationStart) {
         AnimatorSet reveal = new AnimatorSet();
 
         Rect stashedBounds = new Rect();
@@ -349,8 +366,8 @@
             boolean isQsb = child == mTaskbarView.getQsb();
 
             // Crop the icons to/from the nav handle shape.
-            reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb)
-                    .setDuration(duration));
+            reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb,
+                    dispatchOnAnimationStart).setDuration(duration));
 
             // Translate the icons to/from their locations as the "nav handle."
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 5902912..a642693 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -27,7 +27,6 @@
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
 import com.android.launcher3.taskbar.TaskbarDragController;
-import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
@@ -45,8 +44,6 @@
     private final TaskbarDragController mDragController;
     private final TaskbarOverlayDragLayer mDragLayer;
 
-    // We automatically stash taskbar when All Apps is opened in gesture navigation mode.
-    private final boolean mWillTaskbarBeVisuallyStashed;
     private final int mStashedTaskbarHeight;
     private final TaskbarUIController mUiController;
 
@@ -60,18 +57,11 @@
         mDragController = new TaskbarDragController(this);
         mDragController.init(controllers);
         mDragLayer = new TaskbarOverlayDragLayer(this);
-
-        TaskbarStashController taskbarStashController = controllers.taskbarStashController;
-        mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing();
-        mStashedTaskbarHeight = taskbarStashController.getStashedHeight();
+        mStashedTaskbarHeight = controllers.taskbarStashController.getStashedHeight();
 
         mUiController = controllers.uiController;
     }
 
-    boolean willTaskbarBeVisuallyStashed() {
-        return mWillTaskbarBeVisuallyStashed;
-    }
-
     int getStashedTaskbarHeight() {
         return mStashedTaskbarHeight;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index b4ec682..add7279 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -185,7 +186,7 @@
      * 2) Sets tappableInsets bottom inset to 0.
      */
     private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
-        if (!mActivity.willTaskbarBeVisuallyStashed()) {
+        if (!DisplayController.isTransientTaskbar(mActivity)) {
             return oldInsets;
         }
         WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index db38cb6..0012d47 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -131,6 +131,11 @@
     }
 
     @Override
+    protected int getHotseatIconColor() {
+        return getExitingAppColor();
+    }
+
+    @Override
     public void onBackGestureAttempted(BackGestureResult result) {
         if (isGestureCompleted()) {
             return;
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index d031677..593e6d9 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -134,7 +134,7 @@
     }
 
     @Override
-    protected int getExitingAppColor() {
+    protected int getHotseatIconColor() {
         return mTutorialFragment.mRootView.mColorOnSurfaceOverview;
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 06d957a..36655d2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -29,6 +29,7 @@
 import android.annotation.RawRes;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
@@ -107,7 +108,7 @@
     @Nullable View mHotseatIconView;
     final ClipIconView mFakeIconView;
     final FrameLayout mFakeTaskView;
-    final AnimatedTaskbarView mFakeTaskbarView;
+    @Nullable final AnimatedTaskbarView mFakeTaskbarView;
     final AnimatedTaskView mFakePreviousTaskView;
     final View mRippleView;
     final RippleDrawable mRippleDrawable;
@@ -149,7 +150,8 @@
         mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
         mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
         mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
-        mFakeTaskbarView = rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
+        mFakeTaskbarView = ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+                ? null : rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
         mFakePreviousTaskView =
                 rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
         mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@@ -269,12 +271,19 @@
     protected abstract int getSwipeActionColor();
 
     @ColorInt
-    protected abstract int getExitingAppColor();
+    protected int getExitingAppColor() {
+        return Color.TRANSPARENT;
+    }
+
+    @ColorInt
+    protected int getHotseatIconColor() {
+        return Color.TRANSPARENT;
+    }
 
     @DrawableRes
     public int getMockAppIconResId() {
         return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                ? R.drawable.redesigned_default_sandbox_app_icon
+                ? R.drawable.redesigned_hotseat_icon
                 : R.drawable.default_sandbox_app_icon;
     }
 
@@ -463,7 +472,7 @@
             mFakeTaskView.removeCallbacks(mFakeTaskViewCallback);
             mFakeTaskViewCallback = null;
         }
-        if (mFakeTaskbarViewCallback != null) {
+        if (mFakeTaskbarViewCallback != null && mFakeTaskbarView != null) {
             mFakeTaskbarView.removeCallbacks(mFakeTaskbarViewCallback);
             mFakeTaskbarViewCallback = null;
         }
@@ -621,7 +630,7 @@
     }
 
     void hideFakeTaskbar(boolean animateToHotseat) {
-        if (!mTutorialFragment.isLargeScreen()) {
+        if (!mTutorialFragment.isLargeScreen() || mFakeTaskbarView == null) {
             return;
         }
         if (mFakeTaskbarViewCallback != null) {
@@ -635,7 +644,7 @@
     }
 
     void showFakeTaskbar(boolean animateFromHotseat) {
-        if (!mTutorialFragment.isLargeScreen()) {
+        if (!mTutorialFragment.isLargeScreen() || mFakeTaskbarView == null) {
             return;
         }
         if (mFakeTaskbarViewCallback != null) {
@@ -670,6 +679,11 @@
         }
     }
 
+    private void updateHotseatChildViewColor(@Nullable View child) {
+        if (child == null) return;
+        child.getBackground().setTint(getHotseatIconColor());
+    }
+
     private void updateDrawables() {
         if (mContext != null) {
             mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable(
@@ -689,6 +703,12 @@
 
             if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
                 mExitingAppView.setBackgroundColor(getExitingAppColor());
+                updateHotseatChildViewColor(mFakeIconView);
+                updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
+                updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
+                updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
+                updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
+                updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
             }
         }
     }
@@ -712,8 +732,10 @@
                         ? R.dimen.gesture_tutorial_tablet_feedback_margin_top
                         : R.dimen.gesture_tutorial_feedback_margin_top);
 
-        mFakeTaskbarView.setVisibility((mTutorialFragment.isLargeScreen()
-                && !ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) ? View.VISIBLE : GONE);
+        if (mFakeTaskbarView != null) {
+            mFakeTaskbarView.setVisibility(
+                    mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
+        }
 
         RelativeLayout.LayoutParams hotseatLayoutParams =
                 (RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 04f83b9..e5bbcb1 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -60,4 +60,9 @@
      * When turned on, we enable Gms Play related logging.
      */
     public static final String GMS_PLAY = "GmsPlay";
+
+    /**
+     * When turned on, we enable AGA related session summary logging.
+     */
+    public static final String AGA_SESSION_SUMMARY_LOG = "AGASessionSummaryLog";
 }
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index c83820b..026766c 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
 import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
+import static com.android.launcher3.util.TestUtil.installDummyAppForUser;
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
@@ -39,6 +40,7 @@
 import com.android.launcher3.allapps.WorkProfileManager;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 
 import org.junit.After;
@@ -69,11 +71,11 @@
 
         String[] tokens = output.split("\\s+");
         mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
-        output = mDevice.executeShellCommand("am start-user " + mProfileUserId);
         StringBuilder logStr = new StringBuilder().append("profileId: ").append(mProfileUserId);
         for (String str : tokens) {
             logStr.append(str).append("\n");
         }
+        installDummyAppForUser(mProfileUserId);
         updateWorkProfileSetupSuccessful("am start-user", output);
 
         Log.d(WORK_TAB_MISSING, "workProfileSuccessful? " + mWorkProfileSetupSuccessful +
@@ -101,6 +103,7 @@
             }
             launcher.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
         });
+        TestUtil.uninstallDummyApp();
         mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
     }
 
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
index 4981795..f8cd995 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -58,8 +58,13 @@
 
 public class TestUtil {
     public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
+    public static final int DEFAULT_USER_ID = 0;
 
     public static void installDummyApp() throws IOException {
+        installDummyAppForUser(DEFAULT_USER_ID);
+    }
+
+    public static void installDummyAppForUser(int userId) throws IOException {
         // Copy apk from resources to a local file and install from there.
         final Resources resources = getContext().getResources();
         final InputStream in = resources.openRawResource(
@@ -80,7 +85,7 @@
             out.close();
 
             final String result = UiDevice.getInstance(getInstrumentation())
-                    .executeShellCommand("pm install " + apkFilename);
+                    .executeShellCommand("pm install --user " + userId + " " + apkFilename);
             Assert.assertTrue(
                     "Failed to install wellbeing test apk; make sure the device is rooted",
                     "Success".equals(result.replaceAll("\\s+", "")));
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index e4713b2..0c65539 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -21,6 +21,7 @@
 import android.os.Bundle
 import androidx.test.core.app.ApplicationProvider
 import com.android.app.viewcapture.SimpleViewCapture
+import com.android.app.viewcapture.ViewCapture.MAIN_EXECUTOR
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
 import org.junit.rules.TestRule
 import org.junit.runner.Description
@@ -69,7 +70,9 @@
                     // Clean up ViewCapture references here rather than in onActivityDestroyed so
                     // test code can access view hierarchy capture. onActivityDestroyed would delete
                     // view capture data before FailureWatcher could output it as a test artifact.
-                    windowListenerCloseables.onEach(SafeCloseable::close)
+                    // This is on the main thread to avoid a race condition where the onDrawListener
+                    // is removed while onDraw is running, resulting in an IllegalStateException.
+                    MAIN_EXECUTOR.execute { windowListenerCloseables.onEach(SafeCloseable::close) }
                 }
             }
         }