Merge "Update TestProtocol.REQUEST_CLEAR_DATA to properly clear the workspace" into udc-qpr-dev
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 7d7054f..c6e2d8c 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -20,7 +20,6 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3">
-    <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="26"/>
     <!--
     Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
     Refer comments around specific entries on how to extend individual components.
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 225b4cd..672440f 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -13,155 +13,163 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<androidx.constraintlayout.widget.ConstraintLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:theme="@style/GestureTutorialActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
-    android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
-    android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
-    android:background="?androidprv:attr/materialColorSurfaceContainer">
+    android:background="?androidprv:attr/materialColorSurfaceContainer"
+    android:fitsSystemWindows="true">
 
     <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_home_button"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
-        android:layout_marginBottom="24dp"
-        android:background="@drawable/gesture_tutorial_menu_home_button_background"
-        android:clipToOutline="true"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
+        android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
+        android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
+        android:clipToPadding="false">
 
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_back_button">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_home_step_shape"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
-            android:id="@+id/gesture_tutorial_menu_home_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/home_gesture_tutorial_title"
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_home_button"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+            android:layout_marginBottom="24dp"
+            android:background="@drawable/gesture_tutorial_menu_home_button_background"
+            android:clipToOutline="true"
 
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/guideline"
             app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_back_button">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_home_step_shape"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
+                android:id="@+id/gesture_tutorial_menu_home_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/home_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_back_button"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+            android:layout_marginBottom="24dp"
+            android:background="@drawable/gesture_tutorial_menu_back_button_background"
+            android:clipToOutline="true"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/guideline"
+            app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_home_button"
+            app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_overview_button">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_back_step_shape"
+                android:layout_marginBottom="@dimen/gesture_tutorial_menu_back_shape_bottom_margin"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
+                android:id="@+id/gesture_tutorial_menu_back_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/back_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_overview_button"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:layout_marginBottom="24dp"
+            android:background="@drawable/gesture_tutorial_menu_overview_button_background"
+            android:clipToOutline="true"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/guideline"
+            app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_back_button"
+            app:layout_constraintEnd_toEndOf="parent">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_overview_step_shape"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
+                android:id="@+id/gesture_tutorial_menu_overview_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/overview_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+
+            app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
+
+        <Button
+            style="@style/TextAppearance.GestureTutorial.ButtonLabel"
+            android:id="@+id/gesture_tutorial_menu_done_button"
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_marginVertical="16dp"
+            android:text="@string/gesture_tutorial_action_button_label"
+            android:background="@drawable/gesture_tutorial_action_button_background"
+            android:backgroundTint="?androidprv:attr/materialColorPrimary"
+            android:stateListAnimator="@null"
+
+            app:layout_constraintTop_toBottomOf="@id/guideline"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"/>
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_back_button"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
-        android:layout_marginBottom="24dp"
-        android:background="@drawable/gesture_tutorial_menu_back_button_background"
-        android:clipToOutline="true"
-
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline"
-        app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_home_button"
-        app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_overview_button">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_back_step_shape"
-            android:layout_marginBottom="@dimen/gesture_tutorial_menu_back_shape_bottom_margin"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
-            android:id="@+id/gesture_tutorial_menu_back_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/back_gesture_tutorial_title"
-
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_overview_button"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:layout_marginBottom="24dp"
-        android:background="@drawable/gesture_tutorial_menu_overview_button_background"
-        android:clipToOutline="true"
-
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline"
-        app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_back_button"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_overview_step_shape"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
-            android:id="@+id/gesture_tutorial_menu_overview_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/overview_gesture_tutorial_title"
-
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-
-        app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
-
-    <Button
-        style="@style/TextAppearance.GestureTutorial.ButtonLabel"
-        android:id="@+id/gesture_tutorial_menu_done_button"
-        android:layout_width="wrap_content"
-        android:layout_height="40dp"
-        android:layout_marginVertical="16dp"
-        android:text="@string/gesture_tutorial_action_button_label"
-        android:background="@drawable/gesture_tutorial_action_button_background"
-        android:backgroundTint="?androidprv:attr/materialColorPrimary"
-        android:stateListAnimator="@null"
-
-        app:layout_constraintTop_toBottomOf="@id/guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 2c312a7..685a151 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -41,6 +41,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fillViewport="true"
+        android:fitsSystemWindows="true"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -95,7 +96,6 @@
                 style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginBottom="24dp"
                 android:text="@string/allset_hint"
                 android:textSize="@dimen/allset_page_swipe_up_text_size"
                 android:gravity="center_horizontal"
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index cf78b1b..c8ee6e9 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -13,154 +13,161 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<androidx.constraintlayout.widget.ConstraintLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:theme="@style/GestureTutorialActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
-    android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
-    android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
     android:background="?androidprv:attr/materialColorSurfaceContainer"
-    android:clipToPadding="false">
+    android:fitsSystemWindows="true">
 
     <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_home_button"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:background="@drawable/gesture_tutorial_menu_home_button_background"
-        android:clipToOutline="true"
-        app:layout_constraintVertical_chainStyle="packed"
+        android:layout_height="match_parent"
+        android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
+        android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
+        android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
+        android:clipToPadding="false">
 
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_back_button"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_home_step_shape"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
-            android:id="@+id/gesture_tutorial_menu_home_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/home_gesture_tutorial_title"
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_home_button"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:background="@drawable/gesture_tutorial_menu_home_button_background"
+            android:clipToOutline="true"
+            app:layout_constraintVertical_chainStyle="packed"
 
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_back_button"
             app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_home_step_shape"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
+                android:id="@+id/gesture_tutorial_menu_home_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/home_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_back_button"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
+            android:background="@drawable/gesture_tutorial_menu_back_button_background"
+            android:clipToOutline="true"
+
+            app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_home_button"
+            app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_overview_button"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_back_step_shape"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
+                android:id="@+id/gesture_tutorial_menu_back_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/back_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/gesture_tutorial_menu_overview_button"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+            android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
+            android:background="@drawable/gesture_tutorial_menu_overview_button_background"
+            android:clipToOutline="true"
+
+            app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_back_button"
+            app:layout_constraintBottom_toTopOf="@id/guideline"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/gesture_tutorial_overview_step_shape"
+                android:scaleType="fitXY"
+                android:adjustViewBounds="true"
+
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+            <TextView
+                style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
+                android:id="@+id/gesture_tutorial_menu_overview_button_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/overview_gesture_tutorial_title"
+
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"/>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+
+            app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
+
+        <Button
+            style="@style/TextAppearance.GestureTutorial.ButtonLabel"
+            android:id="@+id/gesture_tutorial_menu_done_button"
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_marginVertical="16dp"
+            android:text="@string/gesture_tutorial_action_button_label"
+            android:background="@drawable/gesture_tutorial_action_button_background"
+            android:backgroundTint="?androidprv:attr/materialColorPrimary"
+            android:stateListAnimator="@null"
+
+            app:layout_constraintTop_toBottomOf="@id/guideline"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"/>
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_back_button"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
-        android:background="@drawable/gesture_tutorial_menu_back_button_background"
-        android:clipToOutline="true"
-
-        app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_home_button"
-        app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_overview_button"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_back_step_shape"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
-            android:id="@+id/gesture_tutorial_menu_back_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/back_gesture_tutorial_title"
-
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/gesture_tutorial_menu_overview_button"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/gesture_tutorial_menu_button_height"
-        android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
-        android:background="@drawable/gesture_tutorial_menu_overview_button_background"
-        android:clipToOutline="true"
-
-        app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_back_button"
-        app:layout_constraintBottom_toTopOf="@id/guideline"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/gesture_tutorial_overview_step_shape"
-            android:scaleType="fitXY"
-            android:adjustViewBounds="true"
-
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-        <TextView
-            style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
-            android:id="@+id/gesture_tutorial_menu_overview_button_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/overview_gesture_tutorial_title"
-
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-
-        app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
-
-    <Button
-        style="@style/TextAppearance.GestureTutorial.ButtonLabel"
-        android:id="@+id/gesture_tutorial_menu_done_button"
-        android:layout_width="wrap_content"
-        android:layout_height="40dp"
-        android:layout_marginVertical="16dp"
-        android:text="@string/gesture_tutorial_action_button_label"
-        android:background="@drawable/gesture_tutorial_action_button_background"
-        android:backgroundTint="?androidprv:attr/materialColorPrimary"
-        android:stateListAnimator="@null"
-
-        app:layout_constraintTop_toBottomOf="@id/guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 5c77de7..153c1ac 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -144,6 +145,7 @@
 import com.android.quickstep.util.SurfaceTransaction;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
 import com.android.quickstep.util.SurfaceTransactionApplier;
+import com.android.quickstep.util.TaskRestartedDuringLaunchListener;
 import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.FloatingWidgetView;
 import com.android.quickstep.views.RecentsView;
@@ -299,6 +301,12 @@
         boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
         RunnableList onEndCallback = new RunnableList();
 
+        // Handle the case where an already visible task is launched which results in no transition
+        TaskRestartedDuringLaunchListener restartedListener =
+                new TaskRestartedDuringLaunchListener();
+        restartedListener.register(onEndCallback::executeAllAndDestroy);
+        onEndCallback.add(restartedListener::unregister);
+
         mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
         ItemInfo tag = (ItemInfo) v.getTag();
         if (tag != null && tag.shouldUseBackgroundAnimation()) {
@@ -1203,14 +1211,15 @@
         return false;
     }
 
-    private boolean hasMultipleTargetsWithMode(RemoteAnimationTarget[] targets, int mode) {
+    private boolean shouldPlayFallbackClosingAnimation(RemoteAnimationTarget[] targets) {
         int numTargets = 0;
         for (RemoteAnimationTarget target : targets) {
-            if (target.mode == mode) {
+            if (target.mode == MODE_CLOSING) {
                 numTargets++;
-            }
-            if (numTargets > 1) {
-                return true;
+                if (numTargets > 1 || target.windowConfiguration.getWindowingMode()
+                        == WINDOWING_MODE_MULTI_WINDOW) {
+                    return true;
+                }
             }
         }
         return false;
@@ -1597,7 +1606,7 @@
             boolean playFallBackAnimation = (launcherView == null
                     && launcherIsForceInvisibleOrOpening)
                     || mLauncher.getWorkspace().isOverlayShown()
-                    || hasMultipleTargetsWithMode(appTargets, MODE_CLOSING);
+                    || shouldPlayFallbackClosingAnimation(appTargets);
 
             boolean playWorkspaceReveal = true;
             boolean skipAllAppsScale = false;
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 34316db..023486f 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.appprediction;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
+
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -36,7 +38,6 @@
 import com.android.launcher3.allapps.FloatingHeaderRow;
 import com.android.launcher3.allapps.FloatingHeaderView;
 import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.keyboard.FocusIndicatorHelper;
 import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
 import com.android.launcher3.model.data.ItemInfo;
@@ -106,22 +107,12 @@
                 mActivityContext.getAppsView().getAppsStore().unregisterIconContainer(this);
             }
         }
-
-        // Set the predicted row in All Apps' text line to 1.
-        if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()
-                || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) {
-            for (int i = 0; i < getChildCount(); i++) {
-                BubbleTextView icon = (BubbleTextView) getChildAt(i);
-                icon.setMaxLines(1);
-            }
-        }
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
                 MeasureSpec.EXACTLY));
-        updateVisibility();
     }
 
     @Override
@@ -231,6 +222,7 @@
             icon.reset();
             if (predictionCount > i) {
                 icon.setVisibility(View.VISIBLE);
+                icon.setDisplay(DISPLAY_PREDICTION_ROW);
                 icon.applyFromWorkspaceItem(mPredictedApps.get(i));
             } else {
                 icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
diff --git a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java b/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
index b47ef47..4d0bee6 100644
--- a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
+++ b/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
@@ -20,7 +20,10 @@
 import static android.app.PendingIntent.FLAG_ONE_SHOT;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
 
+import static com.android.launcher3.Utilities.allowBGLaunch;
+
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.Context;
@@ -91,9 +94,10 @@
     }
 
     public void deliverResult(Context context, int resultCode, Intent data) {
+        ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
         try {
             if (mPICallback != null) {
-                mPICallback.send(context, resultCode, data);
+                mPICallback.send(context, resultCode, data, null, null, null, options.toBundle());
             }
         } catch (CanceledException e) {
             Log.e(TAG, "Unable to send back result", e);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 31af1ce..43aceec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -579,6 +579,8 @@
                 Executors.MAIN_EXECUTOR.getHandler(), null,
                 elapsedRealTime -> callbacks.executeAllAndDestroy());
         options.setSplashScreenStyle(splashScreenStyle);
+        options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
         return new ActivityOptionsWrapper(options, callbacks);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 8a8e21f..1e3f4f1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -48,6 +48,8 @@
     private var showingArrow: Boolean = false
     private var arrowDrawable: ShapeDrawable
 
+    var width: Float = 0f
+
     init {
         paint.color = context.getColor(R.color.taskbar_background)
         paint.flags = Paint.ANTI_ALIAS_FLAG
@@ -59,8 +61,11 @@
         pointerSize = res.getDimension(R.dimen.bubblebar_pointer_size)
 
         shadowAlpha =
-            if (Utilities.isDarkTheme(context)) DARK_THEME_SHADOW_ALPHA
-            else LIGHT_THEME_SHADOW_ALPHA
+            if (Utilities.isDarkTheme(context)) {
+                DARK_THEME_SHADOW_ALPHA
+            } else {
+                LIGHT_THEME_SHADOW_ALPHA
+            }
 
         arrowDrawable =
             ShapeDrawable(TriangleShape.create(pointerSize, pointerSize, /* pointUp= */ true))
@@ -102,7 +107,7 @@
         // Draw background.
         val radius = backgroundHeight / 2f
         canvas.drawRoundRect(
-            0f,
+            canvas.width.toFloat() - width,
             0f,
             canvas.width.toFloat(),
             canvas.height.toFloat(),
@@ -132,4 +137,8 @@
     override fun setColorFilter(colorFilter: ColorFilter?) {
         paint.colorFilter = colorFilter
     }
+
+    fun setArrowAlpha(alpha: Int) {
+        arrowDrawable.paint.alpha = alpha
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 8d20705..58c67e3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar.bubbles;
 
+import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -66,8 +67,8 @@
     //  if it's smaller than 5.
     private static final int MAX_BUBBLES = 5;
     private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
+    private static final int WIDTH_ANIMATION_DURATION_MS = 200;
 
-    private final TaskbarActivityContext mActivityContext;
     private final BubbleBarBackground mBubbleBarBackground;
 
     // The current bounds of all the bubble bar.
@@ -90,6 +91,10 @@
 
     private final Rect mTempRect = new Rect();
 
+    // An animator that represents the expansion state of the bubble bar, where 0 corresponds to the
+    // collapsed state and 1 to the fully expanded state.
+    private final ValueAnimator mWidthAnimator = ValueAnimator.ofFloat(0, 1);
+
     // We don't reorder the bubbles when they are expanded as it could be jarring for the user
     // this runnable will be populated with any reordering of the bubbles that should be applied
     // once they are collapsed.
@@ -110,7 +115,7 @@
 
     public BubbleBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mActivityContext = ActivityContext.lookupContext(context);
+        TaskbarActivityContext activityContext = ActivityContext.lookupContext(context);
 
         mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
         mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
@@ -118,9 +123,39 @@
         mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
         setClipToPadding(false);
 
-        mBubbleBarBackground = new BubbleBarBackground(mActivityContext,
+        mBubbleBarBackground = new BubbleBarBackground(activityContext,
                 getResources().getDimensionPixelSize(R.dimen.bubblebar_size));
         setBackgroundDrawable(mBubbleBarBackground);
+
+        mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
+        mWidthAnimator.addUpdateListener(animation -> {
+            updateChildrenRenderNodeProperties();
+            invalidate();
+        });
+        mWidthAnimator.addListener(new Animator.AnimatorListener() {
+            @Override
+            public void onAnimationCancel(Animator animation) {
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBubbleBarBackground.showArrow(mIsBarExpanded);
+                if (!mIsBarExpanded && mReorderRunnable != null) {
+                    mReorderRunnable.run();
+                    mReorderRunnable = null;
+                }
+                updateWidth();
+            }
+
+            @Override
+            public void onAnimationRepeat(Animator animation) {
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mBubbleBarBackground.showArrow(true);
+            }
+        });
     }
 
     @Override
@@ -146,7 +181,7 @@
         return mBubbleBarBounds;
     }
 
-    // TODO: (b/273592694) animate it
+    // TODO: (b/280605790) animate it
     @Override
     public void addView(View child, int index, ViewGroup.LayoutParams params) {
         if (getChildCount() + 1 > MAX_BUBBLES) {
@@ -155,27 +190,55 @@
             removeViewInLayout(getChildAt(getChildCount() - 2));
         }
         super.addView(child, index, params);
+        updateWidth();
+    }
+
+    // TODO: (b/283309949) animate it
+    @Override
+    public void removeView(View view) {
+        super.removeView(view);
+        updateWidth();
+    }
+
+    private void updateWidth() {
+        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
+        setLayoutParams(lp);
     }
 
     /**
      * Updates the z order, positions, and badge visibility of the bubble views in the bar based
      * on the expanded state.
      */
-    // TODO: (b/273592694) animate it
     private void updateChildrenRenderNodeProperties() {
+        final float widthState = (float) mWidthAnimator.getAnimatedValue();
+        final float currentWidth = getWidth();
+        final float expandedWidth = expandedWidth();
+        final float collapsedWidth = collapsedWidth();
         int bubbleCount = getChildCount();
         final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
         for (int i = 0; i < bubbleCount; i++) {
             BubbleView bv = (BubbleView) getChildAt(i);
             bv.setTranslationY(ty);
+
+            // the position of the bubble when the bar is fully expanded
+            final float expandedX = i * (mIconSize + mIconSpacing);
+            // the position of the bubble when the bar is fully collapsed
+            final float collapsedX = i * mIconOverlapAmount;
+
             if (mIsBarExpanded) {
-                final float tx = i * (mIconSize + mIconSpacing);
-                bv.setTranslationX(tx);
-                bv.setZ(0);
+                // where the bubble will end up when the animation ends
+                final float targetX = currentWidth - expandedWidth + expandedX;
+                bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
+                // if we're fully expanded, set the z level to 0
+                if (widthState == 1f) {
+                    bv.setZ(0);
+                }
                 bv.showBadge();
             } else {
+                final float targetX = currentWidth - collapsedWidth + collapsedX;
+                bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
                 bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
-                bv.setTranslationX(i * mIconOverlapAmount);
                 if (i > 0) {
                     bv.hideBadge();
                 } else {
@@ -183,13 +246,33 @@
                 }
             }
         }
+
+        // update the arrow position
+        final float collapsedArrowPosition = arrowPositionForSelectedWhenCollapsed();
+        final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded();
+        final float interpolatedWidth =
+                widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
+        if (mIsBarExpanded) {
+            // when the bar is expanding, the selected bubble is always the first, so the arrow
+            // always shifts with the interpolated width.
+            final float arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
+            mBubbleBarBackground.setArrowPosition(arrowPosition);
+        } else {
+            final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
+            final float arrowPosition =
+                    targetPosition + widthState * (expandedArrowPosition - targetPosition);
+            mBubbleBarBackground.setArrowPosition(arrowPosition);
+        }
+
+        mBubbleBarBackground.setArrowAlpha((int) (255 * widthState));
+        mBubbleBarBackground.setWidth(interpolatedWidth);
     }
 
     /**
      * Reorders the views to match the provided list.
      */
     public void reorder(List<BubbleView> viewOrder) {
-        if (isExpanded()) {
+        if (isExpanded() || mWidthAnimator.isRunning()) {
             mReorderRunnable = () -> doReorder(viewOrder);
         } else {
             doReorder(viewOrder);
@@ -249,6 +332,16 @@
         }
     }
 
+    private float arrowPositionForSelectedWhenExpanded() {
+        final int index = indexOfChild(mSelectedBubbleView);
+        return getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
+    }
+
+    private float arrowPositionForSelectedWhenCollapsed() {
+        final int index = indexOfChild(mSelectedBubbleView);
+        return getPaddingStart() + index * (mIconOverlapAmount) + mIconSize / 2f;
+    }
+
     @Override
     public void setOnClickListener(View.OnClickListener listener) {
         mOnClickListener = listener;
@@ -266,18 +359,16 @@
     /**
      * Sets whether the bubble bar is expanded or collapsed.
      */
-    // TODO: (b/273592694) animate it
     public void setExpanded(boolean isBarExpanded) {
         if (mIsBarExpanded != isBarExpanded) {
             mIsBarExpanded = isBarExpanded;
             updateArrowForSelected(/* shouldAnimate= */ false);
             setOrUnsetClickListener();
-            if (!isBarExpanded && mReorderRunnable != null) {
-                mReorderRunnable.run();
-                mReorderRunnable = null;
+            if (isBarExpanded) {
+                mWidthAnimator.start();
+            } else {
+                mWidthAnimator.reverse();
             }
-            mBubbleBarBackground.showArrow(mIsBarExpanded);
-            requestLayout(); // trigger layout to reposition views & update size for expansion
         }
     }
 
@@ -288,19 +379,16 @@
         return mIsBarExpanded;
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+    private float expandedWidth() {
         final int childCount = getChildCount();
-        final float iconWidth = mIsBarExpanded
-                ? (childCount * (mIconSize + mIconSpacing))
-                : mIconSize + ((childCount - 1) * mIconOverlapAmount);
-        final int totalWidth = (int) iconWidth + getPaddingStart() + getPaddingEnd();
-        setMeasuredDimension(totalWidth, MeasureSpec.getSize(heightMeasureSpec));
+        final int horizontalPadding = getPaddingStart() + getPaddingEnd();
+        return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
+    }
 
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            measureChild(child, (int) mIconSize, (int) mIconSize);
-        }
+    private float collapsedWidth() {
+        final int childCount = getChildCount();
+        final int horizontalPadding = getPaddingStart() + getPaddingEnd();
+        return mIconSize + ((childCount - 1) * mIconOverlapAmount) + horizontalPadding;
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index a5ba815..582b795 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -344,11 +344,13 @@
 
     @Override
     public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
-        // Only pause is taskbar controller is not present
+        // Only pause is taskbar controller is not present until the transition (if it exists) ends
         mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
         RunnableList result = super.startActivitySafely(v, intent, item);
-        if (getTaskbarUIController() == null && result == null) {
-            mHotseatPredictionController.setPauseUIUpdate(false);
+        if (result == null) {
+            if (getTaskbarUIController() == null) {
+                mHotseatPredictionController.setPauseUIUpdate(false);
+            }
         } else {
             result.add(() -> mHotseatPredictionController.setPauseUIUpdate(false));
         }
@@ -1105,6 +1107,8 @@
         activityOptions.options.setLaunchDisplayId(
                 (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
                         : Display.DEFAULT_DISPLAY);
+        activityOptions.options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
         addLaunchCookie(item, activityOptions.options);
         return activityOptions;
     }
@@ -1117,6 +1121,8 @@
                 Executors.MAIN_EXECUTOR.getHandler(), null,
                 elapsedRealTime -> callbacks.executeAllAndDestroy());
         options.setSplashScreenStyle(splashScreenStyle);
+        options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
         return new ActivityOptionsWrapper(options, callbacks);
     }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 13da40a..5784c37 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,6 +18,7 @@
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
@@ -267,7 +268,9 @@
 
     @Override
     public boolean allowAllAppsFromOverview() {
-        return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get();
+        return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
+                // If floating search bar would not show in overview, don't allow all apps gesture.
+                && OVERVIEW.areElementsVisible(getCreatedActivity(), FLOATING_SEARCH_BAR);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 8a9c3c8..7cb6eb6 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -275,6 +275,8 @@
         activityOptions.options.setLaunchDisplayId(
                 (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
                         : Display.DEFAULT_DISPLAY);
+        activityOptions.options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
         mHandler.postDelayed(mAnimationStartTimeoutRunnable, RECENTS_ANIMATION_TIMEOUT);
         return activityOptions;
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 7693e69..1448a52 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -239,7 +239,7 @@
     public void onDisplayInfoChanged(Context context, Info info, int flags) {
         if ((flags & (CHANGE_ROTATION | CHANGE_NAVIGATION_MODE)) != 0) {
             mMode = info.navigationMode;
-            mNavBarPosition = new NavBarPosition(mContext, mMode, info);
+            mNavBarPosition = new NavBarPosition(mMode, info);
 
             if (mMode == NO_BUTTON) {
                 mExclusionListener.register();
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bfe52dd..c9bad38 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -473,16 +473,14 @@
                     throw new IllegalStateException(
                             "Expected task to be showing, but it is " + mode);
                 }
-                if (change.getParent() == null) {
-                    throw new IllegalStateException("Initiating multi-split launch but the split"
-                            + "root of " + taskId + " is already visible or has broken hierarchy.");
-                }
             }
             if (taskId == initialTaskId) {
-                splitRoot1 = transitionInfo.getChange(change.getParent());
+                splitRoot1 = change.getParent() == null ? change :
+                        transitionInfo.getChange(change.getParent());
             }
             if (taskId == secondTaskId) {
-                splitRoot2 = transitionInfo.getChange(change.getParent());
+                splitRoot2 = change.getParent() == null ? change :
+                        transitionInfo.getChange(change.getParent());
             }
         }
 
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 66f5c00..8a87f63 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -42,7 +42,7 @@
         mActivity = activity;
         NavigationMode sysUINavigationMode = DisplayController.getNavigationMode(mActivity);
         if (sysUINavigationMode == NavigationMode.NO_BUTTON) {
-            NavBarPosition navBarPosition = new NavBarPosition(mActivity, sysUINavigationMode,
+            NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
                     DisplayController.INSTANCE.get(mActivity).getInfo());
             mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
                     true /* disableHorizontalSwipe */, navBarPosition,
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index 5202529..c9c64b6 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -103,7 +103,8 @@
         mStateCallback = new MultiStateCallback(STATE_NAMES);
         mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
                 this::endRemoteAnimation);
-        mStateCallback.runOnceAtState(STATE_FLING_FINISHED, this::onFlingFinished);
+        mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
+                this::onFlingFinished);
 
         mSwipeDetector = new SingleAxisSwipeDetector(mContext, this, VERTICAL);
         mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 42b0edf..9f6119c 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -252,6 +252,10 @@
         binder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
         binder.setOverviewTargetChangeListener(binder::preloadOverviewForSUWAllSet);
         binder.preloadOverviewForSUWAllSet();
+        TaskbarManager taskbarManager = binder.getTaskbarManager();
+        if (taskbarManager != null) {
+            mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
+        }
     }
 
     @Override
@@ -327,13 +331,9 @@
         mRootView.setAlpha(alpha);
         mRootView.setTranslationY((alpha - 1) * mSwipeUpShift);
 
-        TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
-        if (mLauncherStartAnim == null && taskbarManager != null) {
-            mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
-        }
         if (mLauncherStartAnim != null) {
-            mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange(
-                    mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN));
+            mLauncherStartAnim.setPlayFraction(
+                    FAST_OUT_SLOW_IN.getInterpolation(mSwipeProgress.value));
         }
         maybeResumeOrPauseBackgroundAnimation();
     }
diff --git a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
index 46f79b1..c19d44a 100644
--- a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
@@ -19,7 +19,6 @@
 import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE;
 import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU;
 
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -28,33 +27,17 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 
 /** Displays the gesture nav tutorial menu. */
 public final class MenuFragment extends GestureSandboxFragment {
 
-    @NonNull private Rect mInsets = new Rect();
-
-    @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mInsets = InvariantDeviceProfile.INSTANCE.get(getContext())
-                .getDeviceProfile(getContext()).getInsets();
-    }
-
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
-        View root = inflater.inflate(
+        final View root = inflater.inflate(
                 R.layout.gesture_tutorial_step_menu, container, false);
 
-        root.setPadding(
-                root.getPaddingLeft() + mInsets.left,
-                root.getPaddingTop() + mInsets.top,
-                root.getPaddingRight() + mInsets.right,
-                root.getPaddingBottom() + mInsets.bottom);
-
         root.findViewById(R.id.gesture_tutorial_menu_home_button).setOnClickListener(
                 v -> launchTutorialStep(TutorialController.TutorialType.HOME_NAVIGATION));
         root.findViewById(R.id.gesture_tutorial_menu_back_button).setOnClickListener(
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 63e41d5..c4a2216 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -60,12 +60,11 @@
     NavBarGestureHandler(Context context) {
         mContext = context;
         DisplayController.Info displayInfo = DisplayController.INSTANCE.get(mContext).getInfo();
-        final int displayRotation = displayInfo.rotation;
         Point currentSize = displayInfo.currentSize;
         mDisplaySize.set(currentSize.x, currentSize.y);
         mSwipeUpTouchTracker =
                 new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
-                        new NavBarPosition(mContext, NavigationMode.NO_BUTTON, displayRotation),
+                        new NavBarPosition(NavigationMode.NO_BUTTON, displayInfo),
                         null /*onInterceptTouch*/, this);
         mMotionPauseDetector = new MotionPauseDetector(context);
 
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
index a89e7e3..9418512 100644
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
@@ -16,9 +16,7 @@
 package com.android.quickstep.util;
 
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
-import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
 
-import android.content.Context;
 import android.view.Surface;
 
 import com.android.launcher3.util.DisplayController.Info;
@@ -29,26 +27,22 @@
  */
 public class NavBarPosition {
 
-    private final boolean mIsLargeScreen;
+    private final boolean mIsTablet;
     private final NavigationMode mMode;
     private final int mDisplayRotation;
 
-    public NavBarPosition(Context context, NavigationMode mode, Info info) {
-        this(context, mode, info.rotation);
-    }
-
-    public NavBarPosition(Context context, NavigationMode mode, int displayRotation) {
-        mIsLargeScreen = isLargeScreen(context);
+    public NavBarPosition(NavigationMode mode, Info info) {
+        mIsTablet = info.isTablet(info.realBounds);
         mMode = mode;
-        mDisplayRotation = displayRotation;
+        mDisplayRotation = info.rotation;
     }
 
     public boolean isRightEdge() {
-        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsLargeScreen;
+        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsTablet;
     }
 
     public boolean isLeftEdge() {
-        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsLargeScreen;
+        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsTablet;
     }
 
     public float getRotation() {
diff --git a/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java
new file mode 100644
index 0000000..91e8376
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep.util;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
+import com.android.quickstep.RecentsModel;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
+
+/**
+ * This class tracks the failure of a task launch through the Launcher.startActivitySafely() call,
+ * in an edge case in which a task may already be visible on screen (ie. in PIP) and no transition
+ * will be run in WM, which results in expected callbacks to not be processed.
+ *
+ * We transiently register a task stack listener during a task launch and if the restart signal is
+ * received, then the registered callback will be notified.
+ */
+public class TaskRestartedDuringLaunchListener implements TaskStackChangeListener {
+
+    private static final String TAG = "TaskRestartedDuringLaunchListener";
+
+    private @NonNull Runnable mTaskRestartedCallback = null;
+
+    /**
+     * Registers a failure listener callback if it detects a scenario in which an app launch
+     * resulted in an already existing task to be "restarted".
+     */
+    public void register(@NonNull Runnable taskRestartedCallback) {
+        TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+        mTaskRestartedCallback = taskRestartedCallback;
+    }
+
+    /**
+     * Unregisters the failure listener.
+     */
+    public void unregister() {
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
+        mTaskRestartedCallback = null;
+    }
+
+    @Override
+    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+        if (wasVisible) {
+            Log.d(TAG, "Detected activity restart during launch for task=" + task.taskId);
+            mTaskRestartedCallback.run();
+            unregister();
+        }
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 7492ab8..a67d787 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -62,7 +62,6 @@
 import com.android.launcher3.util.rule.SamplerRule;
 import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.util.rule.ViewCaptureAnalysisRule;
 import com.android.launcher3.util.rule.ViewCaptureRule;
 import com.android.quickstep.views.RecentsView;
 
@@ -123,8 +122,7 @@
                 .outerRule(new SamplerRule())
                 .around(new NavigationModeSwitchRule(mLauncher))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
-                .around(viewCaptureRule)
-                .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
+                .around(viewCaptureRule);
 
         mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
                 getHomeIntentInPackage(context),
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 95ebd94..82b0b8d 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,5 +21,4 @@
     android:layout_height="match_parent"
     android:theme="@style/HomeScreenElementTheme"
     android:importantForAccessibility="no"
-    android:preferKeepClear="true"
     launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 76a1239..73e392d 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -85,6 +85,7 @@
             <enum name="taskbar" value="5" />
             <enum name="search_result_tall" value="6" />
             <enum name="search_result_small" value="7" />
+            <enum name="prediction_row" value="8" />
         </attr>
         <attr name="centerVertically" format="boolean" />
     </declare-styleable>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 05d434e..2356bcc 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -94,11 +94,12 @@
         IconLabelDotView, DraggableView, Reorderable {
 
     private static final int DISPLAY_WORKSPACE = 0;
-    private static final int DISPLAY_ALL_APPS = 1;
+    public static final int DISPLAY_ALL_APPS = 1;
     private static final int DISPLAY_FOLDER = 2;
     protected static final int DISPLAY_TASKBAR = 5;
     private static final int DISPLAY_SEARCH_RESULT = 6;
     private static final int DISPLAY_SEARCH_RESULT_SMALL = 7;
+    public static final int DISPLAY_PREDICTION_ROW = 8;
 
     private static final float MIN_LETTER_SPACING = -0.05f;
     private static final int MAX_SEARCH_LOOP_COUNT = 20;
@@ -211,7 +212,7 @@
             setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
             defaultIconSize = grid.iconSizePx;
             setCenterVertically(grid.iconCenterVertically);
-        } else if (mDisplay == DISPLAY_ALL_APPS) {
+        } else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW) {
             setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
             setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
@@ -402,7 +403,7 @@
      *  Only if actual text can be displayed in two line, the {@code true} value will be effective.
      */
     protected boolean shouldUseTwoLine() {
-        return (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() && mDisplay == DISPLAY_ALL_APPS)
+        return  (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() && mDisplay == DISPLAY_ALL_APPS)
                 || (FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()
                 && mDisplay == DISPLAY_SEARCH_RESULT);
     }
@@ -424,10 +425,10 @@
         }
     }
 
-    /** This is used for testing to forcefully set the display to ALL_APPS */
+    /** This is used for testing to forcefully set the display. */
     @VisibleForTesting
-    public void setDisplayAllApps() {
-        mDisplay = DISPLAY_ALL_APPS;
+    public void setDisplay(int display) {
+        mDisplay = display;
     }
 
     /**
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bd47fca..814a0f9 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -164,7 +164,7 @@
     public int iconSizePx;
     public int iconTextSizePx;
     public int iconDrawablePaddingPx;
-    public int iconDrawablePaddingOriginalPx;
+    private final int mIconDrawablePaddingOriginalPx;
     public boolean iconCenterVertically;
 
     public float cellScaleToFit;
@@ -456,7 +456,7 @@
             cellStyle = context.obtainStyledAttributes(R.style.CellStyleDefault,
                     R.styleable.CellStyle);
         }
-        iconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
+        mIconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
                 R.styleable.CellStyle_iconDrawablePadding, 0);
         cellStyle.recycle();
 
@@ -883,7 +883,6 @@
         iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid;
 
         updateIconSize(1f, res);
-
         updateWorkspacePadding();
 
         // Check to see if the icons fit within the available height.
@@ -925,6 +924,25 @@
                 + cellLayoutPaddingPx.left + cellLayoutPaddingPx.right;
     }
 
+    private int getNormalizedIconDrawablePadding() {
+        // TODO(b/235886078): workaround needed because of this bug
+        // Icons are 10% larger on XML than their visual size,
+        // so remove that extra space to get labels closer to the correct padding
+        int iconVisibleSizePx = (int) Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
+        return Math.max(0, mIconDrawablePaddingOriginalPx - ((iconSizePx - iconVisibleSizePx) / 2));
+    }
+
+    private int getNormalizedFolderChildDrawablePaddingPx(int textHeight) {
+        // TODO(b/235886078): workaround needed because of this bug
+        // Icons are 10% larger on XML than their visual size,
+        // so remove that extra space to get labels closer to the correct padding
+        int drawablePadding = (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3;
+
+        int iconVisibleSizePx = Math.round(ICON_VISIBLE_AREA_FACTOR * folderChildIconSizePx);
+        int iconSizeDiff = folderChildIconSizePx - iconVisibleSizePx;
+        return Math.max(0, drawablePadding - iconSizeDiff / 2);
+    }
+
     /**
      * Updating the iconSize affects many aspects of the launcher layout, such as: iconSizePx,
      * iconTextSizePx, iconDrawablePaddingPx, cellWidth/Height, allApps* variants,
@@ -937,43 +955,36 @@
 
         // Workspace
         final boolean isVerticalLayout = isVerticalBarLayout();
-        iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale);
         cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale);
-        int cellTextAndPaddingHeight =
-                iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
 
         if (mIsResponsiveGrid) {
-            int cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
-
             cellWidthPx = mResponsiveWidthSpec.getCellSizePx();
             cellHeightPx = mResponsiveHeightSpec.getCellSizePx();
 
             if (cellWidthPx < iconSizePx) {
                 // get a smaller icon size
                 iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
-                // calculate new cellContentHeight
-                cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
             }
 
+            iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+            int iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
+            int cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
+
             while (iconSizePx > mIconSizeSteps.minimumIconSize()
                     && cellContentHeight > cellHeightPx) {
-                int extraHeightRequired = cellContentHeight - cellHeightPx;
-                int newPadding = iconDrawablePaddingPx - extraHeightRequired;
-                if (newPadding >= 0) {
-                    // Responsive uses the padding without scaling
-                    iconDrawablePaddingPx = iconDrawablePaddingOriginalPx = newPadding;
-                    cellTextAndPaddingHeight =
-                            iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
-                } else {
+                iconDrawablePaddingPx -= cellContentHeight - cellHeightPx;
+                if (iconDrawablePaddingPx < 0) {
                     // get a smaller icon size
                     iconSizePx = mIconSizeSteps.getNextLowerIconSize(iconSizePx);
+                    iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
                 }
                 // calculate new cellContentHeight
-                cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
+                cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
             }
 
             cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
         } else if (mIsScalableGrid) {
+            iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
             cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale);
             cellHeightPx = pxFromDp(inv.minCellSize[mTypeIndex].y, mMetrics, scale);
 
@@ -995,6 +1006,8 @@
                 }
             }
 
+            int cellTextAndPaddingHeight =
+                    iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
             int cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
             if (cellHeightPx < cellContentHeight) {
                 // If cellHeight no longer fit iconSize, reduce borderSpace to make cellHeight
@@ -1030,6 +1043,7 @@
             desiredWorkspaceHorizontalMarginPx =
                     (int) (desiredWorkspaceHorizontalMarginOriginalPx * scale);
         } else {
+            iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
             cellWidthPx = iconSizePx + iconDrawablePaddingPx;
             cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR)
                     + iconDrawablePaddingPx
@@ -1103,7 +1117,7 @@
         if (mIsScalableGrid) {
             allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
             allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
-            allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
+            allAppsIconDrawablePaddingPx = getNormalizedIconDrawablePadding();
             allAppsCellWidthPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].x, mMetrics, scale);
 
             if (allAppsCellWidthPx < allAppsIconSizePx) {
@@ -1145,7 +1159,7 @@
     private void updateAllAppsWithResponsiveMeasures() {
         allAppsIconSizePx = iconSizePx;
         allAppsIconTextSizePx = iconTextSizePx;
-        allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
+        allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
 
         allAppsBorderSpacePx = new Point(
                 mAllAppsResponsiveWidthSpec.getGutterPx(),
@@ -1244,6 +1258,32 @@
                     mResponsiveHeightSpec.getGutterPx());
 
             folderContentPaddingLeftRight = mResponsiveFolderWidthSpec.getStartPaddingPx();
+
+            // Reduce icon width if it's wider than the expected folder cell width
+            if (folderCellWidthPx < folderChildIconSizePx) {
+                folderChildIconSizePx = mIconSizeSteps.getIconSmallerThan(folderCellWidthPx);
+            }
+
+            // Recalculating padding and cell height
+            folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
+            int folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
+                    + textHeight;
+
+            // Reduce the icon in height when it's taller than the expected cell height
+            while (folderChildIconSizePx > mIconSizeSteps.minimumIconSize()
+                    && folderCellContentHeight > folderCellHeightPx) {
+                folderChildDrawablePaddingPx -= folderCellContentHeight - folderCellHeightPx;
+                if (folderChildDrawablePaddingPx < 0) {
+                    // get a smaller icon size
+                    folderChildIconSizePx = mIconSizeSteps.getNextLowerIconSize(
+                            folderChildIconSizePx);
+                    folderChildDrawablePaddingPx =
+                            getNormalizedFolderChildDrawablePaddingPx(textHeight);
+                }
+                // calculate new cellContentHeight
+                folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
+                        + textHeight;
+            }
         } else if (mIsScalableGrid) {
             if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
                 folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
@@ -1261,6 +1301,8 @@
             folderFooterHeightPx = roundPxValueFromFloat(folderFooterHeightPx * scale);
 
             folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x;
+
+            folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
         } else {
             int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
                     * scale);
@@ -1277,10 +1319,8 @@
                             res.getDimensionPixelSize(R.dimen.folder_footer_height_default)
                                     * scale);
 
+            folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
         }
-
-        folderChildDrawablePaddingPx = Math.max(0,
-                (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3);
     }
 
     public void updateInsets(Rect insets) {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index eb1c4d4..9db8c82 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.content.Context.RECEIVER_EXPORTED;
 
 import static com.android.launcher3.LauncherPrefs.ICON_STATE;
 import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
@@ -26,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.LauncherApps;
@@ -38,7 +40,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.IconProvider;
@@ -112,8 +113,9 @@
                 new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
         modelChangeReceiver.register(mContext, Intent.ACTION_LOCALE_CHANGED,
                 ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
-        if (FeatureFlags.IS_STUDIO_BUILD) {
-            modelChangeReceiver.register(mContext, ACTION_FORCE_ROLOAD);
+        if (BuildConfig.IS_STUDIO_BUILD) {
+            mContext.registerReceiver(modelChangeReceiver, new IntentFilter(ACTION_FORCE_ROLOAD),
+                    RECEIVER_EXPORTED);
         }
         mOnTerminateCallback.add(() -> mContext.unregisterReceiver(modelChangeReceiver));
 
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 177f883..427eaa3 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -277,7 +277,7 @@
         @JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "", true)
         @JvmField
         val ALL_APPS_OVERVIEW_THRESHOLD =
-            nonRestorableItem(LauncherAppState.KEY_ALL_APPS_OVERVIEW_THRESHOLD, 200, true)
+            nonRestorableItem(LauncherAppState.KEY_ALL_APPS_OVERVIEW_THRESHOLD, 180, true)
         @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, true)
         @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
         @JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0)
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e41d8f9..4f5de05 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -24,6 +24,7 @@
 
 import android.annotation.TargetApi;
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.app.Person;
 import android.app.WallpaperManager;
 import android.content.Context;
@@ -561,6 +562,17 @@
     }
 
     /**
+     * Utility method to allow background activity launch for the provided activity options
+     */
+    public static ActivityOptions allowBGLaunch(ActivityOptions options) {
+        if (ATLEAST_U) {
+            options.setPendingIntentBackgroundActivityStartMode(
+                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+        }
+        return options;
+    }
+
+    /**
      * Returns the full drawable for info without any flattening or pre-processing.
      *
      * @param shouldThemeIcon If true, will theme icons when applicable
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index d78e453..5e48177 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -102,6 +102,12 @@
 
         StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
 
+        // Special case to not expand the search bar when exiting All Apps on phones.
+        if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
+                && mActivityContext.getDeviceProfile().isPhone) {
+            return LauncherState.ALL_APPS.getFloatingSearchBarRestingMarginStart(mActivityContext);
+        }
+
         if (stateManager.isInTransition() && stateManager.getTargetState() != null) {
             return stateManager.getTargetState()
                     .getFloatingSearchBarRestingMarginStart(mActivityContext);
@@ -118,6 +124,12 @@
 
         StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
 
+        // Special case to not expand the search bar when exiting All Apps on phones.
+        if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
+                && mActivityContext.getDeviceProfile().isPhone) {
+            return LauncherState.ALL_APPS.getFloatingSearchBarRestingMarginEnd(mActivityContext);
+        }
+
         if (stateManager.isInTransition() && stateManager.getTargetState() != null) {
             return stateManager.getTargetState()
                     .getFloatingSearchBarRestingMarginEnd(mActivityContext);
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index bb2c37f..f4468fd 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP;
 import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
+import static com.android.launcher3.Utilities.allowBGLaunch;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_LAUNCH_TAP;
 
 import android.app.ActivityOptions;
@@ -26,7 +27,6 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 
@@ -103,10 +103,10 @@
             return;
         }
         final ActivityContext context = ActivityContext.lookupContext(view.getContext());
-        Bundle activityOptions = ActivityOptions.makeClipRevealAnimation(
-                view, 0, 0, view.getWidth(), view.getHeight()).toBundle();
+        ActivityOptions options = allowBGLaunch(ActivityOptions.makeClipRevealAnimation(
+                view, 0, 0, view.getWidth(), view.getHeight()));
         try {
-            intent.send(null, 0, null, null, null, null, activityOptions);
+            intent.send(null, 0, null, null, null, null, options.toBundle());
             context.getStatsLogManager().logger().withItemInfo(mItemInfo)
                     .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP);
         } catch (PendingIntent.CanceledException e) {
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 06da8c5..351ebce 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -16,8 +16,11 @@
 
 package com.android.launcher3.pm;
 
+import static com.android.launcher3.Utilities.allowBGLaunch;
+
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -138,8 +141,10 @@
             }
             IntentSender is = activity.getSystemService(LauncherApps.class)
                     .getShortcutConfigActivityIntent(mInfo);
+            ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
             try {
-                activity.startIntentSenderForResult(is, requestCode, null, 0, 0, 0);
+                activity.startIntentSenderForResult(is, requestCode, null, 0, 0, 0,
+                        options.toBundle());
                 return true;
             } catch (IntentSender.SendIntentException e) {
                 Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index 7c9ab87..eab0969 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -16,10 +16,12 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.Utilities.allowBGLaunch;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.annotation.TargetApi;
+import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.content.Context;
@@ -84,6 +86,8 @@
         final WeakReference<BaseDraggingActivity> weakTarget = new WeakReference<>(mTarget);
         final String actionIdentity = mAction.getTitle() + ", "
                 + mItemInfo.getTargetComponent().getPackageName();
+
+        ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
         try {
             if (DEBUG) Log.d(TAG, "Sending action: " + actionIdentity);
             mAction.getActionIntent().send(
@@ -103,7 +107,9 @@
                             }
                         }
                     },
-                    MAIN_EXECUTOR.getHandler());
+                    MAIN_EXECUTOR.getHandler(),
+                    null,
+                    options.toBundle());
         } catch (PendingIntent.CanceledException e) {
             Log.e(TAG, "Remote action canceled: " + actionIdentity, e);
             Toast.makeText(mTarget, mTarget.getString(
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 67f24aa..d04f5e2 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -18,6 +18,7 @@
 import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
 
 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
+import static com.android.launcher3.Utilities.allowBGLaunch;
 import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_PENDING_INTENT;
@@ -38,7 +39,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
-import android.os.StrictMode;
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
@@ -414,8 +414,7 @@
             }
         }
         ActivityOptions options =
-                ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
-
+                allowBGLaunch(ActivityOptions.makeClipRevealAnimation(v, left, top, width, height));
         options.setLaunchDisplayId(
                 (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
                         : Display.DEFAULT_DISPLAY);
@@ -427,7 +426,7 @@
      * Creates a default activity option and we do not want association with any launcher element.
      */
     default ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
-        ActivityOptions options = ActivityOptions.makeBasic();
+        ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
         if (Utilities.ATLEAST_T) {
             options.setSplashScreenStyle(splashScreenStyle);
         }
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 2ca825c..6acc83d 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -275,9 +275,15 @@
     protected Bundle getConfigurationActivityOptions(@NonNull BaseDraggingActivity activity,
             int widgetId) {
         LauncherAppWidgetHostView view = mViews.get(widgetId);
-        if (view == null) return null;
+        if (view == null) {
+            return activity.makeDefaultActivityOptions(
+                    -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */).toBundle();
+        }
         Object tag = view.getTag();
-        if (!(tag instanceof ItemInfo)) return null;
+        if (!(tag instanceof ItemInfo)) {
+            return activity.makeDefaultActivityOptions(
+                    -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */).toBundle();
+        }
         Bundle bundle = activity.getActivityLaunchOptions(view, (ItemInfo) tag).toBundle();
         bundle.putInt(KEY_SPLASH_SCREEN_STYLE, SPLASH_SCREEN_STYLE_EMPTY);
         return bundle;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index a3ef6e1..c9cd4b6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -891,6 +891,19 @@
         return false;
     }
 
+    /** Gets the sheet for widget picker, which is used for testing. */
+    @VisibleForTesting
+    public View getSheet() {
+        return mContent;
+    }
+
+    /** Opens the first header in widget picker and scrolls to the top of the RecyclerView. */
+    @VisibleForTesting
+    public void openFirstHeader() {
+        mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.selectFirstHeaderEntry();
+        mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
+    }
+
     /** A holder class for holding adapters & their corresponding recycler view. */
     final class AdapterHolder {
         static final int PRIMARY = 0;
diff --git a/tests/Android.bp b/tests/Android.bp
index d518a0e..e7f4084 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -58,7 +58,6 @@
       "src/com/android/launcher3/util/rule/SimpleActivityRule.java",
       "src/com/android/launcher3/util/rule/TestStabilityRule.java",
       "src/com/android/launcher3/util/rule/TISBindRule.java",
-      "src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java",
       "src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index b170061..c8b5a20 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -41,6 +41,17 @@
         </receiver>
 
         <receiver
+            android:name="com.android.launcher3.testcomponent.AppWidgetNoConfigLarge"
+            android:exported="true"
+            android:label="No Config Large">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider"
+                android:resource="@xml/appwidget_no_config_large"/>
+        </receiver>
+
+        <receiver
             android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
             android:exported="true"
             android:label="Hidden widget">
diff --git a/tests/res/xml/appwidget_no_config_large.xml b/tests/res/xml/appwidget_no_config_large.xml
new file mode 100644
index 0000000..b3b69d9
--- /dev/null
+++ b/tests/res/xml/appwidget_no_config_large.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<appwidget-provider
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="1dp"
+    android:minHeight="1dp"
+    android:minResizeWidth="1dp"
+    android:maxResizeWidth="3000dp"
+    android:targetCellHeight="1"
+    android:targetCellWidth="5"
+    android:updatePeriodMillis="86400000"
+    android:initialLayout="@layout/test_layout_appwidget_red"
+    android:previewLayout="@layout/test_layout_appwidget_red"
+    android:resizeMode="horizontal|vertical"
+    android:widgetCategory="home_screen">
+</appwidget-provider>
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index ee05fe6..91a0634 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -164,7 +164,7 @@
         Context c = new ActivityContextWrapper(getApplicationContext());
         DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
         mPrevNumColumns = dp.inv.numColumns;
-        mPrevNumRows = dp.inv.numColumns;
+        mPrevNumRows = dp.inv.numRows;
     }
 
     @After
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index 0a95771..270672f 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -64,8 +64,8 @@
                     "\tinv.numColumns: 5\n" +
                     "\tinv.numSearchContainerColumns: 5\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 165.0px (62.857143dp)\n" +
-                    "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 229.0px (87.2381dp)\n" +
                     "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
                     "\tgetCellSize().y: 379.0px (144.38095dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -76,14 +76,14 @@
                     "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 12.0px (4.571429dp)\n" +
                     "\tinv.numFolderRows: 4\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
                     "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
                     "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
                     "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -139,8 +139,8 @@
                     "\tworkspacePadding.bottom: 203.0px (77.333336dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 722.0px (275.0476dp)\n" +
-                    "\tunscaled extraSpace: 722.0px (275.0476dp)\n" +
+                    "\textraSpace: 752.0px (286.4762dp)\n" +
+                    "\tunscaled extraSpace: 752.0px (286.4762dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -201,8 +201,8 @@
                     "\tinv.numColumns: 5\n" +
                     "\tinv.numSearchContainerColumns: 5\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 165.0px (62.857143dp)\n" +
-                    "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 229.0px (87.2381dp)\n" +
                     "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
                     "\tgetCellSize().y: 383.0px (145.90475dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -213,14 +213,14 @@
                     "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 12.0px (4.571429dp)\n" +
                     "\tinv.numFolderRows: 4\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
                     "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
                     "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
                     "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -276,8 +276,8 @@
                     "\tworkspacePadding.bottom: 245.0px (93.333336dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 743.0px (283.0476dp)\n" +
-                    "\tunscaled extraSpace: 743.0px (283.0476dp)\n" +
+                    "\textraSpace: 773.0px (294.4762dp)\n" +
+                    "\tunscaled extraSpace: 773.0px (294.4762dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -338,7 +338,7 @@
                     "\tinv.numColumns: 5\n" +
                     "\tinv.numSearchContainerColumns: 5\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+                    "\tcellWidthPx: 152.0px (57.904762dp)\n" +
                     "\tcellHeightPx: 166.0px (63.238094dp)\n" +
                     "\tgetCellSize().x: 368.0px (140.19048dp)\n" +
                     "\tgetCellSize().y: 193.0px (73.52381dp)\n" +
@@ -357,7 +357,7 @@
                     "\tfolderCellHeightPx: 205.0px (78.09524dp)\n" +
                     "\tfolderChildIconSizePx: 131.0px (49.904762dp)\n" +
                     "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 9.0px (3.4285715dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -475,7 +475,7 @@
                     "\tinv.numColumns: 5\n" +
                     "\tinv.numSearchContainerColumns: 5\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+                    "\tcellWidthPx: 152.0px (57.904762dp)\n" +
                     "\tcellHeightPx: 166.0px (63.238094dp)\n" +
                     "\tgetCellSize().x: 393.0px (149.71428dp)\n" +
                     "\tgetCellSize().y: 180.0px (68.57143dp)\n" +
@@ -494,7 +494,7 @@
                     "\tfolderCellHeightPx: 192.0px (73.14286dp)\n" +
                     "\tfolderChildIconSizePx: 123.0px (46.857143dp)\n" +
                     "\tfolderChildTextSizePx: 32.0px (12.190476dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 8.0px (3.047619dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 3.0px (1.1428572dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -625,14 +625,14 @@
                     "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
-                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 240.0px (120.0dp)\n" +
                     "\tfolderCellHeightPx: 208.0px (104.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
                     "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 11.0px (5.5dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -649,7 +649,7 @@
                     "\tallAppsCloseDuration: 500\n" +
                     "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
                     "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
                     "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
                     "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
@@ -763,14 +763,14 @@
                     "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
-                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 240.0px (120.0dp)\n" +
                     "\tfolderCellHeightPx: 208.0px (104.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
                     "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 11.0px (5.5dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -787,7 +787,7 @@
                     "\tallAppsCloseDuration: 500\n" +
                     "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
                     "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
                     "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
                     "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
@@ -901,14 +901,14 @@
                     "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
-                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 204.0px (102.0dp)\n" +
                     "\tfolderCellHeightPx: 240.0px (120.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
                     "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 22.0px (11.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -925,7 +925,7 @@
                     "\tallAppsCloseDuration: 500\n" +
                     "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
                     "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
                     "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
                     "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
@@ -1039,14 +1039,14 @@
                     "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
-                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 204.0px (102.0dp)\n" +
                     "\tfolderCellHeightPx: 240.0px (120.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
                     "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 22.0px (11.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -1063,7 +1063,7 @@
                     "\tallAppsCloseDuration: 500\n" +
                     "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
                     "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
-                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
                     "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
                     "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
                     "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
@@ -1170,8 +1170,8 @@
                     "\tinv.numColumns: 4\n" +
                     "\tinv.numSearchContainerColumns: 4\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
-                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+                    "\tcellHeightPx: 218.0px (83.04762dp)\n" +
                     "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
                     "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1182,14 +1182,14 @@
                     "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
                     "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1245,8 +1245,8 @@
                     "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 478.0px (182.09525dp)\n" +
-                    "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+                    "\textraSpace: 498.0px (189.71428dp)\n" +
+                    "\tunscaled extraSpace: 498.0px (189.71428dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1312,8 +1312,8 @@
                     "\tinv.numColumns: 4\n" +
                     "\tinv.numSearchContainerColumns: 4\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
-                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+                    "\tcellHeightPx: 218.0px (83.04762dp)\n" +
                     "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
                     "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1324,14 +1324,14 @@
                     "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
                     "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1387,8 +1387,8 @@
                     "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 478.0px (182.09525dp)\n" +
-                    "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+                    "\textraSpace: 498.0px (189.71428dp)\n" +
+                    "\tunscaled extraSpace: 498.0px (189.71428dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1454,8 +1454,8 @@
                     "\tinv.numColumns: 4\n" +
                     "\tinv.numSearchContainerColumns: 4\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
-                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+                    "\tcellHeightPx: 218.0px (83.04762dp)\n" +
                     "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
                     "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1466,14 +1466,14 @@
                     "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
                     "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1529,8 +1529,8 @@
                     "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 829.0px (315.8095dp)\n" +
-                    "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+                    "\textraSpace: 849.0px (323.42856dp)\n" +
+                    "\tunscaled extraSpace: 849.0px (323.42856dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1592,8 +1592,8 @@
                     "\tinv.numColumns: 4\n" +
                     "\tinv.numSearchContainerColumns: 4\n" +
                     "\tminCellSize: PointF(0.0, 0.0)dp\n" +
-                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
-                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+                    "\tcellHeightPx: 218.0px (83.04762dp)\n" +
                     "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
                     "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
                     "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1604,14 +1604,14 @@
                     "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
                     "\tinv.numFolderRows: 3\n" +
                     "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
                     "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
-                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
                     "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
                     "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1667,8 +1667,8 @@
                     "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
                     "\ticonScale: 1.0px (0.3809524dp)\n" +
                     "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
-                    "\textraSpace: 829.0px (315.8095dp)\n" +
-                    "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+                    "\textraSpace: 849.0px (323.42856dp)\n" +
+                    "\tunscaled extraSpace: 849.0px (323.42856dp)\n" +
                     "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
                     "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
                     "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 66e98f7d..a82b005 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -70,7 +70,6 @@
 import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.ShellCommandRule;
 import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.util.rule.ViewCaptureAnalysisRule;
 import com.android.launcher3.util.rule.ViewCaptureRule;
 
 import org.junit.After;
@@ -209,8 +208,7 @@
         final RuleChain inner = RuleChain
                 .outerRule(new PortraitLandscapeRunner(this))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
-                .around(viewCaptureRule)
-                .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
+                .around(viewCaptureRule);
 
         return TestHelpers.isInLauncherProcess()
                 ? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index fdba4eb..ba17fdc 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_ALL_APPS;
+import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS;
 
 import static org.junit.Assert.assertEquals;
@@ -79,7 +81,6 @@
         mContext = new ActivityContextWrapper(getApplicationContext());
         mBubbleTextView = new BubbleTextView(mContext);
         mBubbleTextView.reset();
-        mBubbleTextView.setDisplayAllApps();
 
         BubbleTextView testView = new BubbleTextView(mContext);
         testView.setTypeface(Typeface.MONOSPACE);
@@ -104,6 +105,7 @@
     public void testEmptyString_flagOn() {
         try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
             mItemInfoWithIcon.title = EMPTY_STRING;
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
@@ -118,6 +120,7 @@
     public void testEmptyString_flagOff() {
         try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
             mItemInfoWithIcon.title = EMPTY_STRING;
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
@@ -134,6 +137,7 @@
             // test string: "Battery Stats"
             mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -149,6 +153,7 @@
             // test string: "Battery Stats"
             mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -164,6 +169,7 @@
             // test string: "flutterappflorafy"
             mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -179,6 +185,7 @@
             // test string: "flutterappflorafy"
             mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -194,6 +201,7 @@
             // test string: "System UWB Field Test"
             mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -209,6 +217,7 @@
             // test string: "System UWB Field Test"
             mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -224,6 +233,7 @@
             // test string: "LEGO®Builder"
             mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -239,6 +249,7 @@
             // test string: "LEGO®Builder"
             mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
             mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
             mBubbleTextView.setTypeface(Typeface.MONOSPACE);
             mBubbleTextView.measure(mLimitedWidth, 0);
             mBubbleTextView.onPreDraw();
@@ -291,4 +302,20 @@
                 breakPoints);
         assertEquals(TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT, newString);
     }
+
+    @Test
+    public void testEnsurePredictionRowIsOneLine() {
+        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
+            // test string: "Battery Stats"
+            mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+            mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
+            mBubbleTextView.applyLabel(mItemInfoWithIcon);
+            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+            mBubbleTextView.measure(mLimitedWidth, 0);
+            mBubbleTextView.onPreDraw();
+            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java b/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java
deleted file mode 100644
index 702757f..0000000
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.util.rule;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-
-import com.android.app.viewcapture.ViewCapture;
-import com.android.app.viewcapture.data.ExportedData;
-
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-
-import java.util.concurrent.ExecutionException;
-
-/**
- * After the test succeeds, the rule looks for anomalies in the data accumulated by ViewCapture
- * that's passed as a parameter. If anomalies are detected, throws an exception and fails the test.
- */
-public class ViewCaptureAnalysisRule extends TestWatcher {
-    @NonNull
-    private final ViewCapture mViewCapture;
-
-    public ViewCaptureAnalysisRule(@NonNull ViewCapture viewCapture) {
-        mViewCapture = viewCapture;
-    }
-
-    @Override
-    protected void succeeded(Description description) {
-        super.succeeded(description);
-        try {
-            analyzeViewCaptureData(mViewCapture.getExportedData(
-                    InstrumentationRegistry.getTargetContext()));
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        } catch (ExecutionException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static void analyzeViewCaptureData(ExportedData viewCaptureData) {
-    }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index 6c06502..8e2aea8 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -36,7 +36,7 @@
  * This rule will not work in OOP tests that don't have access to the activity under test.
  */
 class ViewCaptureRule(var alreadyOpenActivitySupplier: Supplier<Activity?>) : TestRule {
-    val viewCapture = SimpleViewCapture("test-view-capture")
+    private val viewCapture = SimpleViewCapture("test-view-capture")
     var viewCaptureData: ExportedData? = null
         private set
 
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
new file mode 100644
index 0000000..e40fb79
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package com.android.launcher3.util.viewcapture_analysis;
+
+import static com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.diagPathFromRoot;
+
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnalysisNode;
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnomalyDetector;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Anomaly detector that triggers an error when alpha of a view changes too rapidly.
+ * Invisible views are treated as if they had zero alpha.
+ */
+final class AlphaJumpDetector extends AnomalyDetector {
+    // Paths of nodes that are excluded from analysis.
+    private static final Collection<String> PATHS_TO_IGNORE = Set.of(
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
+                    + "/search_results_list_view|SearchResultSmallIconRow",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
+                    + "/search_results_list_view|SearchResultIcon",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|LauncherRecentsView:id/overview_panel|TaskView",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
+                    + "|WidgetsRecyclerView:id/primary_widgets_list_view|WidgetsListHeader:id"
+                    + "/widgets_list_header",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
+                    + "|WidgetsRecyclerView:id/primary_widgets_list_view"
+                    + "|StickyHeaderLayout$EmptySpaceView",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|SearchContainerView:id/apps_view|AllAppsRecyclerView:id"
+                    + "/apps_list_view|BubbleTextView:id/icon",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|LauncherRecentsView:id/overview_panel|ClearAllButton:id"
+                    + "/clear_all",
+            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+                    + ":id/drag_layer|NexusOverviewActionsView:id/overview_actions_view"
+                    + "|LinearLayout:id/action_buttons"
+    );
+    // Minimal increase or decrease of view's alpha between frames that triggers the error.
+    private static final float ALPHA_JUMP_THRESHOLD = 1f;
+
+    @Override
+    void initializeNode(AnalysisNode info) {
+        // If the parent view ignores alpha jumps, its descendants will too.
+        final boolean parentIgnoreAlphaJumps = info.parent != null && info.parent.ignoreAlphaJumps;
+        info.ignoreAlphaJumps = parentIgnoreAlphaJumps
+                || PATHS_TO_IGNORE.contains(diagPathFromRoot(info));
+    }
+
+    @Override
+    void detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN) {
+        // If the view was previously seen, proceed with analysis only if it was present in the
+        // view hierarchy in the previous frame.
+        if (oldInfo != null && oldInfo.frameN != frameN) return;
+
+        final AnalysisNode latestInfo = newInfo != null ? newInfo : oldInfo;
+        if (latestInfo.ignoreAlphaJumps) return;
+
+        final float oldAlpha = oldInfo != null ? oldInfo.alpha : 0;
+        final float newAlpha = newInfo != null ? newInfo.alpha : 0;
+        final float alphaDeltaAbs = Math.abs(newAlpha - oldAlpha);
+
+        if (alphaDeltaAbs >= ALPHA_JUMP_THRESHOLD) {
+            throw new AssertionError(
+                    String.format(
+                            "Alpha jump detected in ViewCapture data: alpha change: %s (%s -> %s)"
+                                    + ", threshold: %s, view: %s",
+                            alphaDeltaAbs, oldAlpha, newAlpha, ALPHA_JUMP_THRESHOLD, latestInfo));
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
new file mode 100644
index 0000000..5a2611c
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+package com.android.launcher3.util.viewcapture_analysis;
+
+import static android.view.View.VISIBLE;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.app.viewcapture.data.ExportedData;
+import com.android.app.viewcapture.data.FrameData;
+import com.android.app.viewcapture.data.ViewNode;
+import com.android.app.viewcapture.data.WindowData;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility that analyzes ViewCapture data and finds anomalies such as views appearing or
+ * disappearing without alpha-fading.
+ */
+public class ViewCaptureAnalyzer {
+    private static final String SCRIM_VIEW_CLASS = "com.android.launcher3.views.ScrimView";
+
+    /**
+     * Detector of one kind of anomaly.
+     */
+    abstract static class AnomalyDetector {
+        /**
+         * Initializes fields of the node that are specific to the anomaly detected by this
+         * detector.
+         */
+        abstract void initializeNode(@NonNull AnalysisNode info);
+
+        /**
+         * Detects anomalies by looking at the last occurrence of a view, and the current one.
+         * null value means that the view. 'oldInfo' and 'newInfo' cannot be both null.
+         * If an anomaly is detected, an exception will be thrown.
+         *
+         * @param oldInfo the view, as seen in the last frame that contained it in the view
+         *                hierarchy before 'currentFrame'. 'null' means that the view is first seen
+         *                in the 'currentFrame'.
+         * @param newInfo the view in the view hierarchy of the 'currentFrame'. 'null' means that
+         *                the view is not present in the 'currentFrame', but was present in earlier
+         *                frames.
+         * @param frameN  number of the current frame.
+         */
+        abstract void detectAnomalies(
+                @Nullable AnalysisNode oldInfo, @Nullable AnalysisNode newInfo, int frameN);
+    }
+
+    // All detectors. They will be invoked in the order listed here.
+    private static final Iterable<AnomalyDetector> ANOMALY_DETECTORS = Arrays.asList(
+            new AlphaJumpDetector()
+    );
+
+    // A view from view capture data converted to a form that's convenient for detecting anomalies.
+    static class AnalysisNode {
+        public String className;
+        public String resourceId;
+        public AnalysisNode parent;
+
+        // Window coordinates of the view.
+        public float left;
+        public float top;
+
+        // Visible scale and alpha, build recursively from the ancestor list.
+        public float scaleX;
+        public float scaleY;
+        public float alpha;
+
+        public int frameN;
+        public ViewNode viewCaptureNode;
+
+        public boolean ignoreAlphaJumps;
+
+        @Override
+        public String toString() {
+            return String.format("window coordinates: (%s, %s), class path from the root: %s",
+                    left, top, diagPathFromRoot(this));
+        }
+    }
+
+    /**
+     * Scans a view capture record and throws an error if an anomaly is found.
+     */
+    public static void assertNoAnomalies(ExportedData viewCaptureData) {
+        final int scrimClassIndex = viewCaptureData.getClassnameList().indexOf(SCRIM_VIEW_CLASS);
+
+        final int windowDataCount = viewCaptureData.getWindowDataCount();
+        for (int i = 0; i < windowDataCount; ++i) {
+            analyzeWindowData(viewCaptureData, viewCaptureData.getWindowData(i), scrimClassIndex);
+        }
+    }
+
+    private static void analyzeWindowData(ExportedData viewCaptureData, WindowData windowData,
+            int scrimClassIndex) {
+        // View hash code => Last seen node with this hash code.
+        // The view is added when we analyze the first frame where it's visible.
+        // After that, it gets updated for every frame where it's visible.
+        // As we go though frames, if a view becomes invisible, it stays in the map.
+        final Map<Integer, AnalysisNode> lastSeenNodes = new HashMap<>();
+
+        for (int frameN = 0; frameN < windowData.getFrameDataCount(); ++frameN) {
+            analyzeFrame(frameN, windowData.getFrameData(frameN), viewCaptureData, lastSeenNodes,
+                    scrimClassIndex);
+        }
+    }
+
+    private static void analyzeFrame(int frameN, FrameData frame, ExportedData viewCaptureData,
+            Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex) {
+        // Analyze the node tree starting from the root.
+        analyzeView(
+                frame.getNode(),
+                /* parent = */ null,
+                frameN,
+                /* leftShift = */ 0,
+                /* topShift = */ 0,
+                viewCaptureData,
+                lastSeenNodes,
+                scrimClassIndex);
+
+        // Analyze transitions when a view visible in the last frame become invisible in the
+        // current one.
+        for (AnalysisNode info : lastSeenNodes.values()) {
+            if (info.frameN == frameN - 1) {
+                if (!info.viewCaptureNode.getWillNotDraw()) {
+                    ANOMALY_DETECTORS.forEach(
+                            detector -> detector.detectAnomalies(
+                                    /* oldInfo = */ info,
+                                    /* newInfo = */ null,
+                                    frameN));
+                }
+            }
+        }
+    }
+
+    private static void analyzeView(ViewNode viewCaptureNode, AnalysisNode parent, int frameN,
+            float leftShift, float topShift, ExportedData viewCaptureData,
+            Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex) {
+        // Skip analysis of invisible views
+        final float parentAlpha = parent != null ? parent.alpha : 1;
+        final float alpha = getVisibleAlpha(viewCaptureNode, parentAlpha);
+        if (alpha <= 0.0) return;
+
+        // Calculate analysis node parameters
+        final int hashcode = viewCaptureNode.getHashcode();
+        final int classIndex = viewCaptureNode.getClassnameIndex();
+
+        final float parentScaleX = parent != null ? parent.scaleX : 1;
+        final float parentScaleY = parent != null ? parent.scaleY : 1;
+        final float scaleX = parentScaleX * viewCaptureNode.getScaleX();
+        final float scaleY = parentScaleY * viewCaptureNode.getScaleY();
+
+        final float left = leftShift
+                + (viewCaptureNode.getLeft() + viewCaptureNode.getTranslationX()) * parentScaleX
+                + viewCaptureNode.getWidth() * (parentScaleX - scaleX) / 2;
+        final float top = topShift
+                + (viewCaptureNode.getTop() + viewCaptureNode.getTranslationY()) * parentScaleY
+                + viewCaptureNode.getHeight() * (parentScaleY - scaleY) / 2;
+
+        // Initialize new analysis node
+        final AnalysisNode newAnalysisNode = new AnalysisNode();
+        newAnalysisNode.className = viewCaptureData.getClassname(classIndex);
+        newAnalysisNode.resourceId = viewCaptureNode.getId();
+        newAnalysisNode.parent = parent;
+        newAnalysisNode.left = left;
+        newAnalysisNode.top = top;
+        newAnalysisNode.scaleX = scaleX;
+        newAnalysisNode.scaleY = scaleY;
+        newAnalysisNode.alpha = alpha;
+        newAnalysisNode.frameN = frameN;
+        newAnalysisNode.viewCaptureNode = viewCaptureNode;
+        ANOMALY_DETECTORS.forEach(detector -> detector.initializeNode(newAnalysisNode));
+
+        // Detect anomalies for the view
+        final AnalysisNode oldAnalysisNode = lastSeenNodes.get(hashcode); // may be null
+        if (frameN != 0 && !viewCaptureNode.getWillNotDraw()) {
+            ANOMALY_DETECTORS.forEach(
+                    detector -> detector.detectAnomalies(oldAnalysisNode, newAnalysisNode, frameN));
+        }
+        lastSeenNodes.put(hashcode, newAnalysisNode);
+
+        // Enumerate children starting from the topmost one. Stop at ScrimView, if present.
+        final float leftShiftForChildren = left - viewCaptureNode.getScrollX();
+        final float topShiftForChildren = top - viewCaptureNode.getScrollY();
+        for (int i = viewCaptureNode.getChildrenCount() - 1; i >= 0; --i) {
+            final ViewNode child = viewCaptureNode.getChildren(i);
+
+            // Don't analyze anything under scrim view because we don't know whether it's
+            // transparent.
+            if (child.getClassnameIndex() == scrimClassIndex) break;
+
+            analyzeView(child, newAnalysisNode, frameN, leftShiftForChildren, topShiftForChildren,
+                    viewCaptureData, lastSeenNodes,
+                    scrimClassIndex);
+        }
+    }
+
+    private static float getVisibleAlpha(ViewNode node, float parenVisibleAlpha) {
+        return node.getVisibility() == VISIBLE
+                ? parenVisibleAlpha * Math.max(0, Math.min(node.getAlpha(), 1))
+                : 0f;
+    }
+
+    private static String classNameToSimpleName(String className) {
+        return className.substring(className.lastIndexOf(".") + 1);
+    }
+
+    static String diagPathFromRoot(AnalysisNode nodeBox) {
+        final StringBuilder path = new StringBuilder(diagPathElement(nodeBox));
+        for (AnalysisNode ancestor = nodeBox.parent; ancestor != null; ancestor = ancestor.parent) {
+            path.insert(0, diagPathElement(ancestor) + "|");
+        }
+        return path.toString();
+    }
+
+    private static String diagPathElement(AnalysisNode nodeBox) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append(classNameToSimpleName(nodeBox.className));
+        if (!"NO_ID".equals(nodeBox.resourceId)) sb.append(":" + nodeBox.resourceId);
+        return sb.toString();
+    }
+}