Merge "WidgetPicker - enable enterprise string cache in standalone activity." into main
diff --git a/Android.bp b/Android.bp
index def024e..bcbd362 100644
--- a/Android.bp
+++ b/Android.bp
@@ -27,7 +27,7 @@
         "android.os.flags-aconfig-java",
         "android.appwidget.flags-aconfig-java",
         "com.android.window.flags.window-aconfig-java",
-    ]
+    ],
 }
 
 // Common source files used to build launcher (java and kotlin)
@@ -69,6 +69,15 @@
     ],
 }
 
+// Source code for quickstep dagger
+filegroup {
+    name: "launcher-quickstep-dagger",
+    srcs: [
+        "quickstep/dagger/**/*.java",
+        "quickstep/dagger/**/*.kt",
+    ],
+}
+
 // Source code for quickstep build with compose enabled, on top of launcher-src
 filegroup {
     name: "launcher-quickstep-compose-enabled-src",
@@ -153,7 +162,7 @@
     soong_config_variables: {
         release_enable_compose_in_launcher: {
             srcs: [
-                ":launcher-compose-enabled-src"
+                ":launcher-compose-enabled-src",
             ],
 
             // Compose dependencies
@@ -166,7 +175,7 @@
             // in compose/launcher3/facade/disabled/.
             conditions_default: {
                 srcs: [
-                    ":launcher-compose-disabled-src"
+                    ":launcher-compose-disabled-src",
                 ],
                 static_libs: [],
             },
@@ -179,7 +188,7 @@
     soong_config_variables: {
         release_enable_compose_in_launcher: {
             srcs: [
-                ":launcher-quickstep-compose-enabled-src"
+                ":launcher-quickstep-compose-enabled-src",
             ],
 
             // Compose dependencies
@@ -192,7 +201,7 @@
             // in compose/quickstep/facade/disabled/.
             conditions_default: {
                 srcs: [
-                    ":launcher-quickstep-compose-disabled-src"
+                    ":launcher-quickstep-compose-disabled-src",
                 ],
                 static_libs: [],
             },
@@ -221,7 +230,7 @@
 android_library {
     name: "launcher-aosp-tapl",
     libs: [
-        "framework-statsd",
+        "framework-statsd.stubs.module_lib",
     ],
     static_libs: [
         "androidx.annotation_annotation",
@@ -322,7 +331,9 @@
         "kotlinx_coroutines",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
-
+        "dagger2",
+        "jsr330",
+        "com_android_systemui_shared_flags_lib",
     ],
     manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
@@ -357,6 +368,7 @@
     sdk_version: "current",
     min_sdk_version: min_launcher3_sdk_version,
     target_sdk_version: "current",
+    plugins: ["dagger2-compiler"],
     privileged: true,
     system_ext_specific: true,
 
@@ -385,13 +397,14 @@
         "quickstep/res",
     ],
     libs: [
-        "framework-statsd",
+        "framework-statsd.stubs.module_lib",
     ],
     static_libs: [
         "Launcher3ResLib",
         "lottie",
         "SystemUISharedLib",
         "SettingsLibSettingsTheme",
+        "dagger2",
     ],
     manifest: "quickstep/AndroidManifest.xml",
     min_sdk_version: "current",
@@ -407,6 +420,7 @@
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
+        ":launcher-quickstep-dagger",
         "go/quickstep/src/**/*.java",
         "go/quickstep/src/**/*.kt",
     ],
@@ -421,7 +435,10 @@
         "QuickstepResLib",
         "androidx.room_room-runtime",
     ],
-    plugins: ["androidx.room_room-compiler-plugin"],
+    plugins: [
+        "androidx.room_room-compiler-plugin",
+        "dagger2-compiler",
+    ],
     manifest: "quickstep/AndroidManifest.xml",
     additional_manifests: [
         "go/AndroidManifest.xml",
@@ -437,16 +454,17 @@
     name: "Launcher3QuickStepLib",
     defaults: [
         "launcher_compose_defaults",
-        "quickstep_compose_defaults"
+        "quickstep_compose_defaults",
     ],
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
+        ":launcher-quickstep-dagger",
         ":launcher-build-config",
     ],
     resource_dirs: [],
     libs: [
-        "framework-statsd",
+        "framework-statsd.stubs.module_lib",
     ],
     // Note the ordering here is important when it comes to resource
     // overriding. We want the most specific resource overrides defined
@@ -458,6 +476,7 @@
     ],
     manifest: "quickstep/AndroidManifest.xml",
     platform_apis: true,
+    plugins: ["dagger2-compiler"],
     min_sdk_version: "current",
     // TODO(b/319712088): re-enable use_resource_processor
     use_resource_processor: false,
@@ -500,7 +519,6 @@
 
 }
 
-
 // Build rule for Launcher3 Go app with quickstep for Android Go devices.
 // Note that the following two rules are exactly same, and should
 // eventually be merged into a single target
@@ -540,6 +558,7 @@
         include_filter: ["com.android.launcher3.*"],
     },
 }
+
 android_app {
     name: "Launcher3QuickStepGo",
     static_libs: ["Launcher3GoLib"],
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 0df6c36..0da2df1 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -316,6 +316,7 @@
     description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
     bug: "355237285"
 }
+
 flag {
     name: "navigate_to_child_preference"
     namespace: "launcher"
@@ -332,3 +333,58 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "letter_fast_scroller"
+    namespace: "launcher"
+    description: "Change fast scroller to a lettered list"
+    bug: "358673724"
+}
+
+flag {
+    name: "enable_desktop_task_alpha_animation"
+    namespace: "launcher"
+    description: "Enables the animation of the desktop task's background view"
+    bug: "320307666"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "ignore_three_finger_trackpad_for_nav_handle_long_press"
+    namespace: "launcher"
+    description: "Ignore three finger trackpad event for nav handle long press"
+    bug: "342143522"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "one_grid_specs"
+    namespace: "launcher"
+    description: "Defines the new specs for grids based on OneGrid"
+    bug: "364711064"
+}
+
+flag {
+    name: "one_grid_mounted_mode"
+    namespace: "launcher"
+    description: "Support a fixed landscape mode for handheld devices"
+    bug: "364711735"
+}
+
+flag {
+    name: "one_grid_rotation_handling"
+    namespace: "launcher"
+    description: "New landscape approach for the workspace using different rows and columns in landscape and portrait"
+    bug: "364711814"
+}
+
+flag {
+    name: "grid_migration_refactor"
+    namespace: "launcher"
+    description: "Refactor grid migration such that the code is simpler to understand and update"
+    bug: "358399271"
+}
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 11740ee..23733a4 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -31,3 +31,20 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_large_desktop_windowing_tile"
+    namespace: "launcher_overview"
+    description: "Makes the desktop tiles larger and moves them to the front of the list in Overview."
+    bug: "353947137"
+}
+
+flag {
+    name: "enable_overview_command_helper_timeout"
+    namespace: "launcher_overview"
+    description: "Enables OverviewCommandHelper new version with a timeout to prevent the queue to be unresponsive."
+    bug: "351122926"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
\ No newline at end of file
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 1b9c661..4c724dc 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -52,6 +52,7 @@
         "tests/src/com/android/quickstep/TaplOverviewIconTest.java",
         "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
         "tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
+        "tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt",
         "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java",
     ],
 }
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..dab2582
--- /dev/null
+++ b/quickstep/dagger/LauncherAppComponent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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.dagger;
+
+import dagger.Component;
+
+import javax.inject.Singleton;
+
+/**
+ * Root component for Dagger injection for Launcher Quickstep.
+ */
+@Singleton
+@Component
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+    /** Builder for quickstep LauncherAppComponent. */
+    @Component.Builder
+    interface Builder extends LauncherBaseAppComponent.Builder {
+        LauncherAppComponent build();
+    }
+}
diff --git a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
similarity index 78%
rename from quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
rename to quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
index 8180293..f204920 100644
--- a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
+++ b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
@@ -15,8 +15,7 @@
 -->
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/materialColorSurfaceBright" />
-    <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+    <solid android:color="@android:color/white" />
+    <corners android:radius="@dimen/keyboard_quick_switch_text_button_radius" />
 </shape>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 613edac..d1e5667 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
-    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
@@ -27,8 +27,8 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:visibility="gone"
-            android:layout_marginStart="@dimen/keyboard_quick_switch_split_view_spacing"
+            android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
 
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..0eccd8e
--- /dev/null
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+    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"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:importantForAccessibility="yes"
+    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:clipToOutline="true"
+    launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/content"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+        app:layout_constraintDimensionRatio="1:1"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <include
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/thumbnail_2"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+        <include
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_2"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:visibility="gone"
+            android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
+
+            app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+        <ImageView
+            android:id="@+id/icon_1"
+            android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+
+            app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+        <ImageView
+            android:id="@+id/icon_2"
+            android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:importantForAccessibility="no"
+            android:visibility="gone"
+            android:scaleType="centerCrop"
+
+            app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 6a99a3b..0551c12 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<TextView
+<com.android.quickstep.views.DigitalWellBeingToast
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     style="@style/TextTitle"
@@ -27,4 +27,5 @@
     android:textColor="?attr/materialColorOnSecondaryFixed"
     android:textSize="14sp"
     android:autoSizeTextType="uniform"
-    android:autoSizeMaxTextSize="14sp"/>
\ No newline at end of file
+    android:autoSizeMaxTextSize="14sp"
+    android:visibility="gone"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
similarity index 68%
rename from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
rename to quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
index c76a2e3..c3f9e54 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
@@ -18,17 +18,20 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
-    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="?attr/materialColorOutline">
+    launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+    launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/keyboard_quick_switch_overview_button_background"
+        android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_text_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorSurfaceContainer"
+        android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -37,10 +40,11 @@
 
         <ImageView
             android:id="@+id/icon"
-            android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
-            android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
-            android:layout_marginBottom="8dp"
-            android:tint="?attr/materialColorOnSurface"
+            android:layout_width="@dimen/keyboard_quick_switch_desktop_icon_size"
+            android:layout_height="@dimen/keyboard_quick_switch_desktop_icon_size"
+            android:layout_marginBottom="4dp"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:src="@drawable/ic_desktop"
 
             app:layout_constraintVertical_chainStyle="packed"
             app:layout_constraintTop_toTopOf="parent"
@@ -49,9 +53,9 @@
             app:layout_constraintEnd_toEndOf="parent"/>
 
         <TextView
-            style="@style/KeyboardQuickSwitchText"
+            style="@style/KeyboardQuickSwitchText.OnTaskView"
             android:id="@+id/text"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:textAlignment="center"
 
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
similarity index 62%
copy from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
copy to quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
index c76a2e3..0b44a2a 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
@@ -18,44 +18,47 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
-    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="?attr/materialColorOutline">
+    launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+    launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/keyboard_quick_switch_overview_button_background"
+        android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_text_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorSurfaceBright"
+        android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent">
 
-        <ImageView
-            android:id="@+id/icon"
-            android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
-            android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
-            android:layout_marginBottom="8dp"
-            android:tint="?attr/materialColorOnSurface"
-
-            app:layout_constraintVertical_chainStyle="packed"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toTopOf="@id/text"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"/>
-
         <TextView
-            style="@style/KeyboardQuickSwitchText"
-            android:id="@+id/text"
+            style="@style/KeyboardQuickSwitchText.LargeText"
+            android:id="@+id/large_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAlignment="center"
 
-            app:layout_constraintTop_toBottomOf="@id/icon"
+            app:layout_constraintVertical_chainStyle="packed"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/small_text"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+        <TextView
+            style="@style/KeyboardQuickSwitchText.OnTaskView"
+            android:id="@+id/small_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="center"
+
+            app:layout_constraintTop_toBottomOf="@id/large_text"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 8f09176..41eb623 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
-    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
@@ -27,8 +27,8 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:visibility="gone"
-            android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
+            android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
 
             app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
             app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..1474949
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+    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"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:importantForAccessibility="yes"
+    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:clipToOutline="true"
+    launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/content"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+        app:layout_constraintDimensionRatio="1:1"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <include
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/thumbnail_2"/>
+
+        <include
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/thumbnail_1"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+        <ImageView
+            android:id="@+id/icon_1"
+            android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+
+            app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+        <ImageView
+            android:id="@+id/icon_2"
+            android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+            android:importantForAccessibility="no"
+            android:visibility="gone"
+            android:scaleType="centerCrop"
+
+            app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 34193d3..760bcdb 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -47,4 +47,7 @@
         android:inflatedId="@id/icon"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content" />
+
+    <include layout="@layout/digital_wellbeing_toast"
+        android:id="@+id/digital_wellbeing_toast"/>
 </com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index cb4b98f..c36a45e 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -73,4 +73,10 @@
         android:inflatedId="@id/bottomRight_icon"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content" />
+
+    <include layout="@layout/digital_wellbeing_toast"
+        android:id="@+id/digital_wellbeing_toast"/>
+
+    <include layout="@layout/digital_wellbeing_toast"
+        android:id="@+id/bottomRight_digital_wellbeing_toast"/>
 </com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
index 784a094..d90d916 100644
--- a/quickstep/res/layout/task_thumbnail.xml
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -15,22 +15,23 @@
 -->
 <com.android.quickstep.task.thumbnail.TaskThumbnailView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent" >
 
-    <ImageView
+    <com.android.quickstep.views.FixedSizeImageView
         android:id="@+id/task_thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:importantForAccessibility="no"
         android:scaleType="matrix"
-        android:visibility="gone"/>
+        android:visibility="invisible"/>
 
     <com.android.quickstep.task.thumbnail.LiveTileView
         android:id="@+id/task_thumbnail_live_tile"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="gone"/>
+        android:visibility="invisible"/>
 
     <View
         android:id="@+id/task_thumbnail_scrim"
@@ -39,16 +40,23 @@
         android:background="@color/overview_foreground_scrim_color"
         android:alpha="0" />
 
-    <FrameLayout
-        android:id="@+id/splash_container"
+    <View
+        android:id="@+id/splash_background"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="gone">
-        <ImageView
-            android:id="@+id/splash_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:importantForAccessibility="no" />
-    </FrameLayout>
+        android:background="@android:color/black"
+        android:alpha="0"
+        android:importantForAccessibility="no" />
+
+    <com.android.quickstep.views.FixedSizeImageView
+        android:id="@+id/splash_icon"
+        android:layout_width="@dimen/task_thumbnail_splash_icon_size"
+        android:layout_height="@dimen/task_thumbnail_splash_icon_size"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:scaleType="fitCenter"
+        android:alpha="0"
+        android:importantForAccessibility="no" />
 </com.android.quickstep.task.thumbnail.TaskThumbnailView>
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index c109328..4122637 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Werkskerm"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Stoor app-paar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies ’n ander app as jy verdeelde skerm wil gebruik"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Kanselleer"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Verlaat verdeeldeskermkeuse"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies nog ’n app as jy verdeelde skerm wil gebruik"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taakbalkverdeler"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Werkskerm"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index f144118..956767ee 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ዴስክቶፕ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"የመተግበሪያ ጥምረትን አስቀምጥ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ ይምረጡ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ይቅር"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ከተከፈለ ማያ ገፅ ምርጫ ይውጡ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"የተከፈለ ማያ ገጽን ለመቀበል ሌላ መተግበሪያ ይምረጡ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"የተግባር አሞሌ አካፋይ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ዴስክቶፕ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 629580f..29d214d 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"كمبيوتر مكتبي"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ما مِن عناصر تم استخدامها مؤخرًا"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"مقسِّم شريط التطبيقات"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"وضع الكمبيوتر المكتبي"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 252697c..912003b 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ডেস্কটপ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"আটাইবোৰ মচক"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবাৰ বিভাজক"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্‌ দেখুৱাওক।}one{আৰু # টা এপ্‌ দেখুৱাওক।}other{আৰু # টা এপ্‌ দেখুৱাওক।}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্‌}one{অধিক এপ্‌}other{অধিক এপ্‌}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 7d7ed56..b89b707 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Tətbiq cütünü saxla"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Ləğv edin"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçimindən çıxın"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"İşləmə paneli ayırıcısı"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index d8f608d..4ef487e 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Računari"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -89,7 +90,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Prevucite nagore da biste otvorili početni ekran"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da biste otišli na početni ekran"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da biste koristili podeljeni ekran"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Otkaži"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlazak iz biranja podeljenog ekrana"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelnik trake zadataka"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index b403e7f..c506acb 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Працоўны стол"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Працоўны стол"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Раздзяляльнік панэлі задач"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Працоўны стол"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 6fb6127..d03e4f7 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"За компютър"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Настолен компютър"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделител на лентата на задачите"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за настолни компютри"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 043c0d6..0c568d9 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ডেস্কটপ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"কোনও সাম্প্রতিক আইটেম নেই"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"অ্যাপ পেয়ার সেভ করুন"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"বাতিল করুন"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"স্প্লিট স্ক্রিন বেছে নেওয়ার বিকল্প থেকে বেরিয়ে আসুন"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবার ডিভাইডার"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index af7fe61..922883e 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Radna površina"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Rotirajte uređaj"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Rotirajte uređaj da završite vodič za navigaciju pokretima"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili krajnjeg lijevog ruba"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili lijevog ruba"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Prevucite s desnog ili lijevog ruba prema sredini ekrana i pustite"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prevući zdesna da se vratite. Sljedeće naučite kako prebacivati između aplikacija."</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Savladali ste pokret za vraćanje. Sljedeće naučite kako prebacivati između aplikacija."</string>
@@ -73,7 +74,7 @@
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Vodite računa da prevučete s donjeg ruba ekrana prema gore"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor duže prije puštanja"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prevucite ravno nagore, a zatim zastanite"</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako koristiti pokrete. Idite u Postavke da isključite pokrete."</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako koristiti pokrete. Da ih isključite, idite u Postavke."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Savladali ste pokret za prebacivanje između aplikacija"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da prebacujete između aplikacija"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Da se prebacujete između aplikacija, prevucite s dna ekrana nagore, zadržite, a zatim pustite."</string>
@@ -89,7 +90,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Prevucite prema gore da odete na početni ekran"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete na početni ekran"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete koristiti <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sistemom"</annotation></string>
@@ -99,7 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da koristite podijeljeni ekran"</string>
-    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Odustani"</string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Otkaži"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlaz iz odabira podijeljenog ekrana"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu apl. da koristite podijeljeni ekran"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake zadataka"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index cc3112a..fe7933b 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escriptori"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Escriptori"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
@@ -59,7 +60,7 @@
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Per tornar a la pantalla anterior, llisca amb dos dits des de l\'extrem esquerre o dret cap al centre de la pantalla."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Torna enrere"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Llisca des de la vora esquerra o dreta cap al centre de la pantalla."</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla"</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Assegura\'t de no aturar-te abans de deixar anar."</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Assegura\'t de lliscar recte cap amunt."</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Has completat el gest per anar a la pantalla d\'inici. Ara, descobreix com pots tornar enrere."</string>
@@ -72,7 +73,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Ben fet!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prova de mantenir premuda la finestra durant més temps abans de deixar-la anar"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assegura\'t de lliscar directament cap amunt i després aturar-te"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assegura\'t de lliscar directament cap amunt i després aturar-te."</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Has après a utilitzar els gestos. Per desactivar-los, ves a Configuració."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Has completat el gest per canviar d\'aplicació"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Llisca per canviar d\'aplicació"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Desa la parella d\'apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Tria una altra aplicació per utilitzar la pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel·la"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Surt de la selecció de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Tria una altra app per utilitzar pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador de la Barra de tasques"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Escriptori"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 546aa1e..3047d05 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
@@ -91,7 +92,7 @@
     <string name="allset_hint" msgid="459504134589971527">"Přejetím nahoru se vrátíte na plochu"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Klepnutím na tlačítko plochy se vrátíte na plochu"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> můžete začít používat"</string>
-    <string name="default_device_name" msgid="6660656727127422487">"zařízení"</string>
+    <string name="default_device_name" msgid="6660656727127422487">"Zařízení"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavení navigace v systému"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Uložit dvojici aplikací"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdělíte klepnutím na jinou aplikaci"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Výběrem další aplikace rozdělíte obrazovku"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Zrušit"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Výběr opuštění rozdělené obrazovky"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vyberte podporovanou aplikaci"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdělovač panelu aplikací"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index ae10343..6e2130c 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computertilstand"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Computer"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Gem appsammenknytning"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Vælg en anden app for at bruge opdelt skærm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuller"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Luk valg af opdelt skærm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Opdeling af proceslinjen"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 03b5bb9..54961fe 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopmodus"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktopmodus"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Abbrechen"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Splitscreen-Auswahl beenden"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für Splitscreen andere App auswählen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktopmodus"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index a717678..6cbb833 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Υπολογιστής"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Υπολογιστής"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
@@ -90,7 +91,7 @@
     <string name="allset_title" msgid="5021126669778966707">"Όλα έτοιμα!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Σύρετε προς τα επάνω για να μεταβείτε στην αρχική σελίδα"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Πατήστε το κουμπί αρχικής οθόνης για να μεταβείτε στην αρχική οθόνη"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το/τη <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε τη <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"συσκευή"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ρυθμίσεις πλοήγησης συστήματος"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Αποθήκ. ζεύγ. εφαρμ."</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Ακύρωση"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Έξοδος από την επιλογή διαχωρισμού οθόνης"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Διαχωριστικό Γραμμής εργαλείων"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Υπολογιστής"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index d28cbf0..dcbaa7a 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index e069b8f..c00e6cd 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index d28cbf0..dcbaa7a 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index d28cbf0..dcbaa7a 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 777db28..2abef91 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎Desktop‎‏‎‎‏‎"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎Desktop‎‏‎‎‏‎"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎Taskbar Divider‎‏‎‎‏‎"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎Move to top/left‎‏‎‎‏‎"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎Move to bottom/right‎‏‎‎‏‎"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎Show # more app.‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎Show # more apps.‎‏‎‎‏‎}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎Show # desktop app.‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎Show # desktop apps.‎‏‎‎‏‎}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎more app‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎more apps‎‏‎‎‏‎}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎Desktop‎‏‎‎‏‎"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="APP_NAME_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎Bubble‎‏‎‎‏‎"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‎Overflow‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 3d78c71..f09fae6 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Computadoras"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cerrar todo"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar vinculación"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de la Barra de tareas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index f878954..356a38b 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de Barra de Tareas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación más}other{aplicaciones más}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 4468533..fccbeda 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Lauaarvuti režiim"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Töölaud"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Tühista"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Jagatud ekraanikuva valikust väljumine"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tegumiriba jagaja"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Lauaarvuti"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index fe138b8..a1d8cc3 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenagailua"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Mahaigaina"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Gorde aplikazio parea"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pantaila zatitua erabiltzeko, aukeratu beste aplikazio bat"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Utzi"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Irten pantaila zatituaren hautapenetik"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitzeko, aukeratu beste aplikazio bat"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Zereginen barraren zatitzailea"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenagailua"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index cb88eba..8f37686 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"حالت رایانه"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"رایانه"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
@@ -103,7 +104,7 @@
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"خروج از انتخاب صفحهٔ دونیمه"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمی‌دهد این کنش انجام شود."</string>
-    <string name="split_widgets_not_supported" msgid="1355743038053053866">"درحال‌حاضر از ابزارک‌ها پشتیبانی نمی‌شود، لطفاً برنامه دیگری را انتخاب کنید"</string>
+    <string name="split_widgets_not_supported" msgid="1355743038053053866">"درحال‌حاضر از ابزاره‌ها پشتیبانی نمی‌شود، لطفاً برنامه دیگری را انتخاب کنید"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گام‌به‌گام پیمایش رد شود؟"</string>
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"می‌توانید آن را بعداً در برنامه <xliff:g id="NAME">%1$s</xliff:g> پیدا کنید"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"لغو"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"جداکننده نوار وظیفه"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"رایانه"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 4d610f2..175a896 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tietokone"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Tietokone"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
@@ -72,7 +73,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Hienoa!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pyyhkäise ylös näytön alareunasta"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Kokeile pitää ikkunaa painettuna pidempään ennen kuin päästät irti"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Muista pyyhkäistä suoraan ylöspäin ja pysähdy sitten"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pyyhkäise suoraan ylöspäin ja pysähdy sitten"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Olet oppinut käyttämään eleitä. Jos haluat laittaa eleet pois päältä, avaa Asetukset."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Olet oppinut sovellusten vaihtamiseleen"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Vaihda sovellusta pyyhkäisemällä"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Peru"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Poistu jaetun näytön valinnasta"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tehtäväpalkin jakaja"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Tietokone"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 179be5f..6d6c67c 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur de bureau"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'appli"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autres applis.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur de bureau"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 8568c40..a395266 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -96,11 +97,10 @@
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer la paire d\'applis"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer une paire d\'applis"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour l\'écran partagé"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Sélectionnez une autre appli pour utiliser l\'écran partagé."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuler"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection de l\'écran partagé"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Sélect. autre appli pour utiliser l\'écran partagé"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de barre des tâches"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index e6400ca..5b04960 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -90,8 +91,8 @@
     <string name="allset_title" msgid="5021126669778966707">"Todo listo"</string>
     <string name="allset_hint" msgid="459504134589971527">"Pasa o dedo cara arriba para ir á pantalla de inicio"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Toca o botón de inicio para ir á pantalla de inicio"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> xa está dispoñible para comezar a utilizar"</string>
-    <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> dispoñible para comezar a utilizar"</string>
+    <string name="default_device_name" msgid="6660656727127422487">"Dispositivo"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración da navegación do sistema"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar parella apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saír da selección de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 2adf594..fc253bd 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ડેસ્કટૉપ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ડેસ્કટૉપ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ઍપની જોડી સાચવો"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"વિભાજિત સ્ક્રીનની સુવિધાનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"રદ કરો"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"\'સ્ક્રીનને વિભાજિત કરો\' પસંદગીમાંથી બહાર નીકળો"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ટાસ્કબાર વિભાજક"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ડેસ્કટૉપ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 56d2b39..30a17db 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करें"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"हाल ही का कोई आइटम नहीं है"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"सभी हटाएं"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिवाइडर"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 97f4ee0..06511e9 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računalo"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Zakrenite uređaj"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Zakrenite uređaj da biste dovršili vodič o navigaciji pokretima"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite da prijeđete prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prijeđite prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvršili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
@@ -70,9 +71,9 @@
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Otvaranje početnog zaslona"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Prijeđite prstom od dna zaslona prema gore"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Sjajno!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pazite da prijeđete prstom prema gore od donjeg ruba zaslona"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Prijeđite prstom prema gore od donjeg ruba zaslona"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor dulje prije podizanja prsta"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pazite da prijeđete prstom ravno prema gore, a zatim zastanete"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prijeđite prstom ravno prema gore, a zatim zastanite"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste koristiti pokrete. Pokrete možete isključiti u postavkama."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Izvršili ste pokret za promjenu aplikacije"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Povlačenje prstom za promjenu aplikacije"</string>
@@ -91,7 +92,7 @@
     <string name="allset_hint" msgid="459504134589971527">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> je spreman za početak upotrebe"</string>
-    <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
+    <string name="default_device_name" msgid="6660656727127422487">"Uređaj"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sustavom"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Podijeli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Računalo"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 2d0bd18..9bd9478 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Asztali"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
@@ -59,7 +60,7 @@
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Ha vissza szeretne térni a legutóbbi képernyőre, csúsztasson gyorsan két ujjal a képernyő bal vagy jobb széléről a közepe felé."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Vissza"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Csúsztasson bal vagy jobb szélről a képernyő közepe felé."</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Csúsztasson felfelé a képernyő aljától."</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Csúsztasson felfelé a képernyő alsó szélétől."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ne álljon meg, mielőtt elengedi a képernyőt."</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Csúsztasson egyenesen felfelé."</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Teljesítette a kezdőképernyőre lépés kézmozdulatát. Most megtanulhatja, hogyan léphet vissza."</string>
@@ -68,9 +69,9 @@
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Csúsztassa ujját felfelé a képernyő aljától. Ez a mozdulat mindig a kezdőképernyőre visz."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Csúsztasson felfelé két ujjal a képernyő aljáról. Ez a kézmozdulat mindig a kezdőképernyőre viszi."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ugrás a kezdőképernyőre"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Húzza ujját felfelé a képernyő aljától."</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Csúsztasson felfelé a képernyő aljától."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Kiváló!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Csúsztasson felfelé a képernyő aljától."</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Csúsztasson felfelé a képernyő alsó szélétől."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Próbálja tovább lenyomva tartani az ablakot, mielőtt elengedi a képernyőt."</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Csúsztasson egyenesen felfelé, majd várjon egy kicsit"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Eddig megismerhette a kézmozdulatok használatát. A kézmozdulatokat a Beállításokban kapcsolhatja ki."</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"App-pár mentése"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Válasszon másik appot a képernyő felosztásához"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Mégse"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Kilépés az osztott képernyő elemeinek kiválasztásából"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Válasszon másik appot a képernyő felosztásához"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Feladatsáv-elválasztó"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Asztali"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 947e34e..e1481ec 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Համակարգիչ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Համակարգիչ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Այստեղ դեռ ոչինչ չկա"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Հավելվածների վահանակի բաժանիչ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Համակարգիչ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 16334ca..f8345b5 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Simpan pasangan apl"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk aplikasi lain untuk memakai layar terpisah"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Batal"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar dari pemilihan layar terpisah"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index ed1cf85..017d108 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Tölva"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Vista forritapar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Veldu annað forrit til að nota skjáskiptingu"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Hætta við"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Loka skjáskiptingu"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Veldu annað forrit til að nota skjáskiptingu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skipting forritastiku"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{forrit til viðbótar}one{forrit til viðbótar}other{forrit til viðbótar}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Skjáborð"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 29a84dd..1983ee3 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Salva coppia di app"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Scegli un\'altra app per usare lo schermo diviso"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annulla"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Esci dalla selezione dello schermo diviso"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Scegli un\'altra app per usare lo schermo diviso"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisore barra delle app"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index e30f7df..a7115e3 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"מחשב"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
@@ -72,8 +73,8 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"מעולה!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"חשוב להחליק למעלה מהקצה התחתון של המסך"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"כדאי לנסות להחזיק את החלון זמן רב יותר לפני שחרור האצבע"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"חשוב להחליק ישר למעלה ואז להמתין"</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"למדת איך להשתמש בתנועות. ניתן להשבית את התנועות ב\'הגדרות\'."</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"חשוב להחליק למעלה בקו ישר ואז לעצור"</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"למדת איך להשתמש בתנועות. אפשר להשבית את התנועות ב\'הגדרות\'."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"השלמת את תנועת המעבר בין האפליקציות"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"יש להחליק כדי לעבור בין אפליקציות"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"כדי לעבור בין אפלקציות, יש להחליק למעלה מתחתית המסך, להחזיק ולאחר מכן לשחרר."</string>
@@ -89,18 +90,17 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"מדריך <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"הכול מוכן!"</string>
     <string name="allset_hint" msgid="459504134589971527">"כדי לחזור לדף הבית, צריך להחליק למעלה"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית יש להקיש על הלחצן הראשי"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית צריך להקיש על הלחצן הראשי"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"הכול מוכן ואפשר להתחיל להשתמש ב<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"מכשיר"</string>
-    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"הגדרות הניווט של המערכת"</annotation></string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"הגדרות הניווט במערכת"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"שיתוף"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
     <string name="action_split" msgid="2098009717623550676">"פיצול"</string>
     <string name="action_save_app_pair" msgid="5974823919237645229">"שמירת צמד אפליקציות"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ביטול"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"יציאה מתצוגת מסך מפוצל"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"המחיצה בסרגל האפליקציות"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"מחשב"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index bb6d07b..fa3c01d 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"デスクトップ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"パソコン"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"タスクバーの区切り"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"パソコン"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 0ffc3e8..a032731 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"დესკტოპი"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"დესკტოპი"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ამოცანათა ზოლის გამყოფი"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"დესკტოპი"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 8bf7111..e1a9e8e 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Жұмыс үстелі"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Қолданбаларды жұптауды сақтау"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Бас тарту"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Экранды бөлу режимінен шығу"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапсырмалар жолағын бөлгіш"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 06cd015..2eb3114 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ដែសថប"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"អេក្រង់ដើម"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់​ការប្រើប្រាស់​កម្មវិធី"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"សម្អាត​ទាំងអស់"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"រក្សាទុកគូកម្មវិធី"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធី​ផ្សេងទៀត ដើម្បីប្រើ​មុខងារបំបែកអេក្រង់"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារ​បំបែកអេក្រង់"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"បោះបង់"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ចាកចេញពីការជ្រើសរើសរបស់មុខងារ​បំបែកអេក្រង់"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារ​បំបែកអេក្រង់"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះ​មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី​ ឬ​ស្ថាប័ន​របស់អ្នកទេ"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"បន្ទាត់​ខណ្ឌចែករបារកិច្ចការ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញ​កម្មវិធី # ទៀត។}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធី​កុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធី​កុំព្យូទ័រ #។}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"អេក្រង់ដើម"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 26f1d6f..bb60620 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್‌ಟಾಪ್"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ಡೆಸ್ಕ್‌ಟಾಪ್"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್‌ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
@@ -73,13 +74,13 @@
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"ಬೆರಳನ್ನು ಮೇಲೆತ್ತುವ ಮೊದಲು ವಿಂಡೋವನ್ನು ಹೆಚ್ಚು ಸಮಯ ಹಿಡಿದಿಡಲು ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ, ನಂತರ ವಿರಾಮಗೊಳಿಸಿ"</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ಗೆಶ್ಚರ್‌ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆಂದು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಗೆಶ್ಚರ್‌ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ಜೆಶ್ಚರ್‌ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆಂದು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಜೆಶ್ಚರ್‌ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"ನೀವು ಆ್ಯಪ್‌ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"ಆ್ಯಪ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ಆ್ಯಪ್‌ಗಳ ನಡುವೆ ಬದಲಿಸಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"ಆ್ಯಪ್‌ಗಳ ನಡುವೆ ಬದಲಿಸಲು, 2 ಬೆರಳುಗಳಿಂದ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"ಆ್ಯಪ್‌ಗಳನ್ನು ಬದಲಿಸಿ"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹೋಲ್ಡ್ ಮಾಡಿ, ನಂತರ ಬಿಡುಗಡೆ ಮಾಡಿ"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹೋಲ್ಡ್ ಮಾಡಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"ಭೇಷ್!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"ಸಂಪೂರ್ಣ ಸಿದ್ಧವಾಗಿದೆ"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"ಮುಗಿದಿದೆ"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ಟಾಸ್ಕ್‌ಬಾರ್ ಡಿವೈಡರ್"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌ಗಳು}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ಡೆಸ್ಕ್‌ಟಾಪ್"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್‌ಫ್ಲೋ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 04fd457..e6a80c3 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"데스크톱"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"데스크톱"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"앱 페어링 저장"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"취소"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"화면 분할 선택 종료"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"태스크 바 분할"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"데스크톱"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index f0156de..98f46ac 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Компьютер"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу параметрлери"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Колдонмолорду сактап коюу"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Жокко чыгаруу"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Тандалган экранды бөлүүдөн чыгуу"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапшырмалар панелин бөлгүч"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index e862b9e..2239f8b 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -83,7 +83,7 @@
     <dimen name="taskbar_suw_frame">96dp</dimen>
     <dimen name="taskbar_suw_insets">24dp</dimen>
 
-    <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
-    <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+    <!-- Keyboard Quick Switch -->
+    <dimen name="keyboard_quick_switch_taskview_width">217.6dp</dimen>
 
 </resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 81a52b1..b3ca116 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ເດັສທັອບ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ເດັສທັອບ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ແຕະແອັບອື່ນເພື່ອໃຊ້ໜ້າຈໍແຍກ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ຍົກເລີກ"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ອອກຈາກາກນເລືອກການແບ່ງໜ້າຈໍ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ເສັ້ນແບ່ງແຖບໜ້າວຽກ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ເດັສທັອບ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index ec45620..4f3f36e 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Stalinis kompiuteris"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Išsaug. progr. porą"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Išskaidyto ekrano režimas palietus kitą programą"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Išskaidyto ekrano režimą naudokite kita programa"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Atšaukti"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Išeiti iš išskaidyto ekrano pasirinkimo"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Išskaidyto ekrano režimą naudokite kita programa"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Užduočių juostos daliklis"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildoma programa}one{papildoma programa}few{papildomos programos}many{papildomos programos}other{papildomų programų}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Stalinis kompiuteris"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 4474e7c..fd75fc4 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Dators"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Darbvirsma"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
@@ -67,7 +68,7 @@
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Vilkšana, lai pārietu uz sākumu"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Ar 2 pirkstiem velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Došanās uz sākuma ekrānu"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Doties uz sākuma ekrānu"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Velciet augšup no ekrāna apakšdaļas."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Lieliski!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Jāvelk augšup no ekrāna apakšmalas."</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Saglabāt pāri"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Atcelt"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izejiet no ekrāna sadalīšanas režīma atlases."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Uzdevumu joslas atdalītājs"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Darbvirsma"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index f503e59..b50277b 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Работна површина"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"За компјутер"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Избриши ги сите"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Зачувај го паров"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Изберете друга апликација за да користите поделен екран"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Откажи"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излези од изборот на поделен екран"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник на „Лента со задачи“"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за компјутер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 5448f60..ef72da1 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്‌ക്ടോപ്പ്"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ഡെസ്‌ക്ടോപ്പ്"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്‌ക്കുക"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ആപ്പ് ജോടി സംരക്ഷിക്കൂ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"സ്പ്ലിറ്റ് സ്ക്രീനിന് മറ്റൊരു ആപ്പിൽ ടാപ്പ് ചെയ്യൂ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കാൻ മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"റദ്ദാക്കുക"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"സ്‌ക്രീൻ വിഭജന തിരഞ്ഞെടുപ്പിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ടാസ്‌ക്ബാർ ഡിവൈഡർ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്‌ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്‌ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ഡെസ്‌ക്ടോപ്പ്"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 18c66d7..2ca2e26 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Дэлгэц"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг арилгах"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ажлын хэсгийг хуваагч"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Дэлгэц"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 45f768a..159368d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अ‍ॅप वापर सेटिंग्ज"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार विभाजक"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{आणखी # अ‍ॅप दाखवा.}other{आणखी # अ‍ॅप्स दाखवा.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्‍कटॉप अ‍ॅप दाखवा.}other{# डेस्‍कटॉप अ‍ॅप्स दाखवा.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अ‍ॅप}other{आणखी अ‍ॅप्स}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 5d56cd1..9a27e51 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
@@ -68,18 +69,18 @@
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Leret ke atas dari bahagian bawah skrin. Gerak isyarat ini sentiasa membawa anda ke Skrin utama."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Leret ke atas dengan 2 jari dari bawah skrin. Gerak isyarat ini sentiasa bawa anda ke Skrin utama."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Pergi ke skrin utama"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Leret ke atas dari bahagian bawah skrin anda"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Leret ke atas dari bahagian bawah skrin"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Syabas!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pastikan anda meleret ke atas dari sisi bahagian bawah skrin"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Cuba tahan tetingkap untuk tempoh yang lebih lama sebelum melepaskan"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pastikan anda meleret terus ke atas, kemudian menjeda"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pastikan anda meleret lurus ke atas, kemudian berhenti seketika"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Anda sudah belajar cara menggunakan gerak isyarat. Untuk mematikan gerak isyarat, pergi ke Tetapan."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Anda telah melengkapkan gerak isyarat menukar apl"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Leret untuk menukar apl"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Untuk beralih antara apl, leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Untuk beralih antara apl, leret ke atas dengan 2 jari dari bawah skrin, tahan, kemudian lepaskan."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Beralih antara apl"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Leret ke atas dari bahagian bawah skrin, tahan, kemudian lepas"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Syabas!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Selesai"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Selesai"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pembahagi Bar Tugas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 06740db..7e298fb 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ဒက်စ်တော့"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ဒက်စ်တော့"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးရှင်းရန်"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ကြိုတင်မှန်းဆထားသော အက်ပ်− <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"သင့်စက်ကို လှည့်ပါ"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"လက်ဟန်ဖြင့် လမ်းညွှန်ခြင်း ရှင်းလင်းပို့ချချက်အား အပြီးသတ်ရန် သင့်စက်ကို လှည့်ပါ"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်အစွန်း၏ ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်ဘက်အစွန်ဆုံးမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ဖန်သားပြင်၏ ညာ (သို့) ဘယ်အစွန်းမှ အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"နောက်ပြန်သွားရန် ညာဘက်မှပွတ်ဆွဲနည်းကို သိသွားပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"မလုပ်တော့"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ရွေးချယ်မှုမှ ထွက်ရန်"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"မျက်နှာပြင်ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"လုပ်ဆောင်စရာဘား ပိုင်းခြားစနစ်"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ဒက်စ်တော့"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6a31efa..4b982ef 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Skrivebord"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avslutt valg av delt skjerm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Velg en annen app for å bruke delt skjerm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skille for oppgavelinjen"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Datamaskin"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index b4a0136..326222b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटप"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटप"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"एपको पेयर सेभ गर्नुहोस्"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"रद्द गर्नुहोस्"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रिन मोडबाट बाहिरिनुहोस्"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिभाइडर"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string>
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index 2cb633a..eb88310 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -14,16 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
-    <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar">
-        <item name="android:navigationBarColor">@android:color/transparent</item>
-        <item name="android:statusBarColor">@android:color/transparent</item>
-        <item name="android:enforceNavigationBarContrast">false</item>
-        <item name="android:windowLightStatusBar">false</item>
-        <item name="android:windowBackground">@android:color/transparent</item>
-    </style>
+<resources>
 
     <style name="TextAppearance.GestureTutorial.MainTitle.Home"
         parent="TextAppearance.GestureTutorial.MainTitle">
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 0cd8141..8a923b5 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Scheiding voor Taakbalk"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 97b0493..3150ded 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍‍"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ଡେସ୍କଟପ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ଡେସ୍କଟପ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ ବ୍ୟବହାର ସେଟିଂସ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ପୂର୍ବାନୁମାନ କରାଯାଇଥିବା ଆପ୍: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"ଆପଣଙ୍କ ଡିଭାଇସକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"ଜେଶ୍ଚର ନାଭିଗେସନ ଟ୍ୟୁଟୋରିଆଲ ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ଦୟାକରି ଆପଣଙ୍କ ଡିଭାଇସ ରୋଟେଟ କରନ୍ତୁ"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
@@ -72,14 +73,14 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"ବଢ଼ିଆ କାମ!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"ଆପଣ ସ୍କ୍ରିନର ତଳ ଧାରରୁ ଉପରକୁ ସ୍ୱାଇପ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"ୱିଣ୍ଡୋକୁ ରିଲିଜ୍ କରିବା ପୂର୍ବରୁ ଅଧିକ ସମୟ ଧରି ରଖିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ୍ କରି ତା\'ପରେ ବିରତ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ କରି ତା\'ପରେ ବିରତ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ଜେଶ୍ଚରଗୁଡ଼ିକୁ କିପରି ବ୍ୟବହାର କରାଯିବ ଆପଣ ତାହା ଶିଖିଛନ୍ତି। ଜେଶ୍ଚରଗୁଡ଼ିକୁ ବନ୍ଦ କରିବାକୁ, ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"ଆପଣ \'ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ୍ କରିବା ପାଇଁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ଆପ୍ସ ମଧ୍ୟରେ ସୁଇଚ କରିବାକୁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ, ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କରନ୍ତୁ।"</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"ଆପ୍ସ ମଧ୍ୟରେ ସ୍ୱିଚ କରିବାକୁ, 2ଟି ଆଙ୍ଗୁଠିରେ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କର।"</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"ଆପ୍ସ ସୁଇଚ କରନ୍ତୁ"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ଆପଣଙ୍କ ସ୍କ୍ରିନ୍‌ର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ୍ କରନ୍ତୁ"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କରନ୍ତୁ"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"ବହୁତ ବଢ଼ିଆ!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"ସବୁ ପ୍ରସ୍ତୁତ"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"ହୋଇଗଲା"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଚୟନରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ଟାସ୍କବାର ଡିଭାଇଡର"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ଡେସ୍କଟପ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index bd7e4d8..7da7555 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ਡੈਸਕਟਾਪ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ਰੱਦ ਕਰੋ"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਚੋਣ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ਟਾਸਕਬਾਰ ਵਿਭਾਜਕ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ਡੈਸਕਟਾਪ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 942cdde..0cc49e2 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Pulpit"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Pulpit"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Linia dzielenia paska aplikacji"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Pulpit"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 50058c9..33b87df 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Computador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App prevista: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Rode o dispositivo"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Rode o seu dispositivo para concluir o tutorial de navegação por gestos"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize rapidamente a partir da extremidade mais à direita ou mais à esquerda"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize a partir da extremidade mais à direita ou mais à esquerda"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize rapidamente a partir da extremidade esquerda ou direita até ao centro do ecrã e solte"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendeu a deslizar a partir da direita para retroceder. A seguir, saiba como alternar entre apps."</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Concluiu o gesto para retroceder. A seguir, saiba como alternar entre apps."</string>
@@ -58,8 +59,8 @@
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Para voltar ao último ecrã, deslize rapidamente do limite esquerdo ou direito até ao centro do ecrã."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Para voltar ao último ecrã, deslize rapidamente com 2 dedos a partir da extremidade esquerda ou direita até ao centro do ecrã."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Retroceder"</string>
-    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize rapidamente a partir da extremidade esquerda ou direita para o meio do ecrã"</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã"</string>
+    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize a partir da extremidade esquerda ou direita até ao centro do ecrã"</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize a partir do limite inferior do ecrã"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Não faça uma pausa antes de soltar"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Deslize rapidamente com o dedo para cima"</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Concluiu o gesto para aceder ao ecrã principal. A seguir, saiba como retroceder."</string>
@@ -68,18 +69,18 @@
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Deslize rapidamente para cima a partir da parte inferior. Este gesto abre sempre o ecrã principal."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Deslize rapidamente para cima com 2 dedos no fundo do ecrã. Este gesto abre sempre o ecrã principal."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Aceda ao ecrã principal"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Deslize rapidamente para cima a partir da parte inferior do ecrã"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Deslize para cima a partir da parte inferior do ecrã"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Muito bem!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize a partir do limite inferior do ecrã"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Experimente premir a janela durante mais tempo antes de soltar"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Garanta que desliza rapidamente com o dedo para cima e, em seguida, faz uma pausa"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pause"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Aprendeu a utilizar gestos. Para desativar os gestos, aceda às Definições."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Concluiu o gesto para alternar entre apps"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslize rapidamente com o dedo para alternar entre apps"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Para alternar entre apps, deslize para cima sem soltar a partir da parte inferior do ecrã e solte."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Para mudar de app, deslize rapidamente para cima com 2 dedos sem soltar no fundo do ecrã e solte."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Mude de app"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Deslize rapidamente para cima a partir da parte inferior do ecrã sem soltar e, em seguida, solte"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Deslize para cima a partir da parte inferior do ecrã , detenha o gesto e solte"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Muito bem!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Está tudo pronto"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Concluído"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 6ad7b2e..0aa6295 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Modo área de trabalho"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Computador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Remover tudo"</string>
@@ -72,7 +73,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Muito bem!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize da borda inferior da tela para cima"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Mantenha a janela pressionada por mais tempo antes de soltar"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pare"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima em linha reta e pare"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Você aprendeu. Para desativar os gestos, acesse as Configurações."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para mudar de app"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslizar para trocar de app"</string>
@@ -89,7 +90,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Deslize para cima para acessar a tela inicial"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para ir para a tela inicial"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para acessar a tela inicial"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Você já pode começar a usar seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configurações de navegação do sistema"</annotation></string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Salvar par de apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque em outro app para usar a tela dividida"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outro app para usar na tela dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sair da seleção de tela dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolha outro app para usar na tela dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador da Barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 9b264b8..2f9d287 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Computer"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Șterge tot"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Salvează perechea de aplicații"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Alege altă aplicație pentru a folosi ecranul împărțit"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anulează"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ieși din selecția cu ecran împărțit"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Alege altă aplicație pentru ecranul împărțit"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația ta"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separator pentru bara de activități"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicație suplimentară}few{mai multe aplicații}other{mai multe aplicații}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 5bcae00..4054eb7 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Мультиоконный режим"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Мультиоконный режим"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Сохранить приложения"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Отмена"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйдите из режима разделения экрана."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделитель панели задач"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим компьютера"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index b23617f..19b61f7 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ඩෙස්ක්ටොපය"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ඩෙස්ක්ටොපය"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"යෙදුම් යුගල සුරකින්න"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"බෙදුම් තිරය භාවිත කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"අවලංගු කරන්න"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"බෙදීම් තිර තේරීමෙන් පිටවන්න"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්‍රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"කාර්ය තීරු බෙදනය"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ඩෙස්ක්ටොපය"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 278ad0e..0f0ec27 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predpovedaná aplikácia: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Otočte zariadenie"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Otočte zariadenie a dokončite tak návod, ako navigovať gestami"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Musíte potiahnuť z pravého alebo ľavého okraja do stredu obrazovky a potom uvoľniť"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste sa prejsť späť potiahnutím sprava. V ďalšom kroku sa naučíte prepínať aplikácie."</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili ste gesto na prechod späť. V ďalšom kroku sa naučíte, ako prepínať aplikácie."</string>
@@ -58,8 +59,8 @@
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Na poslednú obrazovku prejdete potiahnutím z ľavého alebo pravého okraja do stredu obrazovky."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Na poslednú obrazovku sa vrátite potiahnutím dvoma prstami z ľavého alebo pravého okraja do stredu obrazovky."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Prechod späť"</string>
-    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Potiahnite z ľavého alebo pravého okraja do stredu obrazovky"</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Musíte potiahnuť nahor z dolného okraja obrazovky"</string>
+    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Potiahnite z ľavého alebo pravého okraja do stredu obrazovky."</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Musíte potiahnuť nahor z dolného okraja obrazovky."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Pred uvoľnením nesmiete zastať"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Musíte potiahnuť priamo nahor"</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Dokončili ste gesto prechodu na plochu. Teraz sa naučíte, ako sa vrátiť späť."</string>
@@ -68,18 +69,18 @@
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Potiahnite nahor zdola obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Postiahnite dvoma prstami z dolnej časti obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Prechod na plochu"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Potiahnite z dolnej časti obrazovky nahor"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Potiahnite z dolnej časti obrazovky nahor."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Skvelé!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Musíte potiahnuť nahor z dolného okraja obrazovky"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Skúste okno pred uvoľnením podržať dlhšie"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Musite potiahnuť priamo nahor a potom zastať"</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste sa používať gestá. Gestá môžete vypnúť v nastaveniach."</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Musite potiahnuť priamo nahor a potom zastať."</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste sa používať gestá. Gestá môžete vypnúť v Nastaveniach."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Dokončili ste gesto na prepnutie aplikácií"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prepínanie aplikácií potiahnutím"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Aplikácie môžete prepínať potiahnutím obrazovky zdola nahor, pridržaním a následným uvoľnením."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Aplikácie prepnete potiahnutím dvoma prstami z dolnej časti obrazovky, ich pridržaním a uvoľnením."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Prepnutie aplikácií"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Potiahnite nahor z dolného okraja obrazovky, pridržte a uvoľnite"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Potiahnite nahor z dolného okraja obrazovky, pridržte a uvoľnite."</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Výborne"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Hotovo"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Hotovo"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Uložiť pár aplikácií"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdelíte klepnutím na inú aplikáciu"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Na použitie rozdelenej obrazovky vyberte ďalšiu aplikáciu"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Zrušiť"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ukončite výber rozdelenej obrazovky"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Na použitie rozd. obrazovky vyberte inú aplikáciu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdeľovač panela aplikácií"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ďalšia aplikácia}few{ďalšie aplikácie}many{ďalšie aplikácie}other{ďalšie aplikácie}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 0c201b4..972ced5 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Namizni računalnik"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Namizni način"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelilnik opravilne vrstice"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}two{dodatni aplikaciji}few{dodatne aplikacije}other{dodatnih aplikacij}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Namizni računalnik"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index cd5725d..d2a7281 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopi"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktopi"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Ruaj çiftin e aplikacioneve"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anulo"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Dil nga zgjedhja e ekranit të ndarë"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ky veprim nuk lejohet nga aplikacioni ose organizata jote"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ndarësi i shiritit të detyrave"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 708406b..81204af 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Рачунар"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Рачунари"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
@@ -89,7 +90,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Превуците нагоре да бисте отворили почетни екран"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисте отишли на почетни екран"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"уређај"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Сачувај пар апликација"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Одаберите другу апликацију да бисте користили подељени екран"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Откажи"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излазак из бирања подељеног екрана"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник траке задатака"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Рачунар"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index ef0ef76..5d0c7a3 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Dator"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Dator"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Listan är tom"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avsluta val av delad skärm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Välj en annan app för att använda delad skärm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Avdelare för aktivitetsfältet"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Dator"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 63b5922..e133ba3 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Kompyuta ya Mezani"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Hifadhi jozi ya programu"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Acha"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ondoka kwenye hali ya skrini iliyogawanywa"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Kitenganishi cha Upauzana"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuta ya Mezani"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 5159245..95d0fa9 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"டெஸ்க்டாப்"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"டெஸ்க்டாப்"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
@@ -72,7 +73,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"அருமை!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"திரையின் கீழ் ஓரத்திலிருந்து மேல்நோக்கி ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"விடுவிப்பதற்கு முன்பாக நீண்டநேரம் சாளரத்தை அழுத்திப் பிடித்திருங்கள்"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"மேல்நோக்கி நேராக ஸ்வைப் செய்தபிறகு இடைநிறுத்துவதை உறுதிசெய்துகொள்ளுங்கள்"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"மேல்நோக்கி நேராக ஸ்வைப் செய்தபிறகு சற்றுநேரம் அழுத்திபடியே வைத்திருங்கள்"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"சைகைகளை எப்படி உபயோகிப்பது என்று கற்றுக்கொண்டீர்கள். சைகைகளை முடக்க அமைப்புகளுக்குச் செல்லுங்கள்."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"ஆப்ஸுக்கிடையே மாறும் சைகைப் பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"ஆப்ஸுக்கிடையே மாற ஸ்வைப் செய்யுங்கள்"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தேர்வுசெய்யுங்கள்"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ரத்துசெய்"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"திரைப் பிரிப்பு தேர்வில் இருந்து வெளியேறும்"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"செயல் பட்டிப் பிரிப்பான்"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"டெஸ்க்டாப்"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 8c8e688..116d388 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయండి"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"డెస్క్‌టాప్"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"డెస్క్‌టాప్"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి ఐటెమ్‌లు ఏవీ లేవు"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్‌లు"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"టాస్క్‌బార్ డివైడర్"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{మరో # యాప్‌ను చూడండి.}other{మరో # యాప్‌లను చూడండి.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్‌టాప్ యాప్‌ను చూపండి.}other{# డెస్క్‌టాప్ యాప్‌లను చూపండి.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్‌}other{మరిన్ని యాప్‌లు}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"డెస్క్‌టాప్"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్‌ఫ్లో"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 2c5f9a6..ecdb3b5 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"เดสก์ท็อป"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"เดสก์ท็อป"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
@@ -47,7 +48,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"แอปที่คาดว่าจะใช้: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"หมุนอุปกรณ์ของคุณ"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"โปรดหมุนอุปกรณ์เพื่อทำตามบทแนะนำการนำทางด้วยท่าทางสัมผัสให้เสร็จสมบูรณ์"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ตรวจสอบว่าปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
     <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
@@ -72,7 +73,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"เก่งมาก"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"ปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"ลองแตะหน้าต่างค้างไว้นานขึ้นก่อนปล่อยนิ้ว"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ตรวจสอบว่าปัดขึ้นในแนวตรง แล้วหยุดชั่วคราว"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ปัดขึ้นในแนวตรง แล้วหยุดชั่วคราว"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"คุณรู้วิธีใช้ท่าทางสัมผัสแล้ว หากต้องการปิดท่าทางสัมผัส ให้ไปที่การตั้งค่า"</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"ปัดเพื่อสลับแอป"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ตัวแบ่งแถบงาน"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"เดสก์ท็อป"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 88ebb4a..da646a4 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divider ng Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 6117bfd..7be5464 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Görev Çubuğu Ayırıcısı"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 44170e9..216ae0b 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Робочий стіл"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Комп’ютер"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Зберегти пару"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток."</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Скасувати"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Вийти з режиму розділення екрана"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Розділювач панелі завдань"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Комп’ютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 89cfbbb..2307cb1 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"ڈیسک ٹاپ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"ایپس کے جوڑے کو محفوظ کریں"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"منسوخ کریں"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"اسپلٹ اسکرین کے انتخاب سے باہر نکلیں"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ٹاسک بار ڈیوائیڈر"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"ڈیسک ٹاپ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index e3c7727..9f98b55 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Vazifalar panelini ajratkich"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuter"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 8844fe9..50acbbc 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Máy tính"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Máy tính"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Đường phân chia Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Máy tính"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b52d33b..1b6c4e4 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"桌面设备"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"保存应用组合"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"另外选择一个应用才可使用分屏模式"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"取消"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分屏选择模式"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"另外选择一个应用才可使用分屏模式"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"任务栏分隔线"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面模式"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index a048848..38608e5 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"桌面"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -140,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index a27f2c5..3e46779 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"電腦"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式配對"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇要在分割畫面中使用的另一個應用程式"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"取消"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分割畫面選擇器"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"必須選擇另一個應用程式才能使用分割畫面"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"電腦"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index b5f6abc..120b387 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,6 +22,7 @@
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
     <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
+    <string name="recent_task_desktop" msgid="8081113562549637334">"Ideskithophu"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
@@ -99,8 +100,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Londoloza ukubhangqa i-app"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
-    <skip />
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Khansela"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Phuma ekukhetheni ukuhlukaniswa kwesikrini"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string>
@@ -141,8 +141,8 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Isihlukanisi se-Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
-    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string>
+    <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string>
+    <string name="quick_switch_desktop" msgid="8393802056024499749">"Ideskithophu"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string>
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index ccc7f18..7fd6b5c 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -28,6 +28,7 @@
         <!-- Border color for a keyboard quick switch task views -->
         <attr name="focusBorderColor" format="color" />
         <attr name="hoverBorderColor" format="color" />
+        <attr name="focusBorderRadius" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="ClearAllButton">
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 867ce17..ce3f3ac 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -41,6 +41,8 @@
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
     <!--  The icon size for the focused task, placed in center of touch target  -->
     <dimen name="task_thumbnail_icon_drawable_size">44dp</dimen>
+    <!--  The splash icon size on in Overview when a task is settled in the list -->
+    <dimen name="task_thumbnail_splash_icon_size">52dp</dimen>
     <!--  The border width shown when task is hovered  -->
     <dimen name="task_hover_border_width">4dp</dimen>
     <!--  The space under the focused task icon  -->
@@ -374,6 +376,7 @@
     <dimen name="transient_taskbar_stash_spring_velocity_dp_per_s">400dp</dimen>
     <dimen name="taskbar_tooltip_vertical_padding">8dp</dimen>
     <dimen name="taskbar_tooltip_horizontal_padding">16dp</dimen>
+    <dimen name="taskbar_tooltip_y_offset">4dp</dimen>
 
     <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
     <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
@@ -434,6 +437,7 @@
     <dimen name="bubblebar_stashed_handle_width">55dp</dimen>
     <dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
     <dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
+    <dimen name="bubblebar_stashed_handle_spring_velocity_dp_per_s">@dimen/transient_taskbar_stash_spring_velocity_dp_per_s</dimen>
     <!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
     background appropriately when close to the rounded corner -->
     <dimen name="bubblebar_pointer_visible_size">9dp</dimen>
@@ -484,17 +488,22 @@
     <!-- Keyboard Quick Switch -->
     <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
-    <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+    <dimen name="keyboard_quick_switch_taskview_height">136dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
     <dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
+    <dimen name="keyboard_quick_switch_desktop_icon_size">32dp</dimen>
     <dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
     <dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
     <dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
-    <dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
+    <dimen name="keyboard_quick_switch_view_small_spacing">4dp</dimen>
     <dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
     <dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
     <dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
     <dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
+    <dimen name="keyboard_quick_switch_text_button_width">104dp</dimen>
+    <dimen name="keyboard_quick_switch_text_button_radius">360dp</dimen>
+    <dimen name="keyboard_quick_switch_text_button_horizontal_padding">16dp</dimen>
+    <dimen name="keyboard_quick_switch_text_button_fade_edge_length">20dp</dimen>
 
     <!-- Digital Wellbeing -->
     <dimen name="digital_wellbeing_toast_height">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index d0f474f..f72f3c5 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -327,17 +327,14 @@
     <!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the Taskbar only). -->
     <string name="move_drop_target_bottom_or_right">Move to bottom&#47;right</string>
 
-    <!-- Label for quick switch tile showing how many more apps are available [CHAR LIMIT=NONE] -->
+    <!-- Label for quick switch tile showing how many more apps are available. The number will be displayed above this text. [CHAR LIMIT=NONE] -->
     <string name="quick_switch_overflow">{count, plural,
-            =1{Show # more app.}
-            other{Show # more apps.}
+            =1{more app}
+            other{more apps}
         }</string>
 
-    <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
-    <string name="quick_switch_desktop">{count, plural,
-            =1{Show # desktop app.}
-            other{Show # desktop apps.}
-        }</string>
+    <!-- Label for quick switch tile to launch desktop mode [CHAR LIMIT=NONE] -->
+    <string name="quick_switch_desktop">Desktop</string>
 
     <!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
     <string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 1f4720c..c423d09 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -205,7 +205,7 @@
         <item name="android:textColor">?attr/tutorialSubtitle</item>
     </style>
 
-    <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
+    <style name="AllSetTheme" parent="@style/DynamicColorsBaseLauncherTheme.NoActionBar">
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:enforceNavigationBarContrast">false</item>
@@ -272,10 +272,22 @@
         <item name="lineHeight">20sp</item>
     </style>
 
+    <style name="KeyboardQuickSwitchText.LargeText" parent="KeyboardQuickSwitchText">
+        <item name="android:textSize">32sp</item>
+    </style>
+
     <style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
         <item name="android:textColor">?attr/materialColorOnSurface</item>
     </style>
 
+    <style name="KeyboardQuickSwitchText.OnTaskView" parent="KeyboardQuickSwitchText">
+        <item name="android:requiresFadingEdge">horizontal</item>
+        <item name="android:fadeScrollbars">false</item>
+        <item name="android:fadingEdgeLength">20dp</item>
+        <item name="android:ellipsize">none</item>
+        <item name="android:singleLine">true</item>
+    </style>
+
     <style name="GestureTutorialActivity" parent="@style/AppTheme">
         <item name="background">@android:color/transparent</item>
         <item name="tutorialSubtitle">@android:color/black</item>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index d973149..e940553 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.util.Log;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.RemoteAnimationTarget;
 
@@ -196,6 +197,7 @@
                 if (skipFirstFrame) {
                     // Because t=0 has the app icon in its original spot, we can skip the
                     // first frame and have the same movement one frame earlier.
+                    Log.d("b/311077782", "LauncherAnimationRunner.setAnimation");
                     mAnimator.setCurrentPlayTime(
                             Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
                 }
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 4a1035f..e51c956 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -65,7 +65,6 @@
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
 import static com.android.quickstep.util.AnimUtils.clampToDuration;
 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
@@ -1228,9 +1227,7 @@
      * Registers remote animations used when closing apps to home screen.
      */
     public void registerRemoteTransitions() {
-        if (ENABLE_SHELL_TRANSITIONS) {
-            SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
-        }
+        SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
         if (SEPARATE_RECENTS_ACTIVITY.get()) {
             return;
         }
@@ -1294,9 +1291,7 @@
     }
 
     protected void unregisterRemoteTransitions() {
-        if (ENABLE_SHELL_TRANSITIONS) {
-            SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
-        }
+        SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
         if (SEPARATE_RECENTS_ACTIVITY.get()) {
             return;
         }
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 036568e..955388d 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -20,7 +20,6 @@
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
 
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
@@ -172,11 +171,6 @@
 
     @Override
     protected void registerBackDispatcher() {
-        if (!enablePredictiveBackGesture()) {
-            super.registerBackDispatcher();
-            return;
-        }
-
         getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
                 OnBackInvokedDispatcher.PRIORITY_DEFAULT,
                 new BackAnimationCallback());
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 189deda..f7da34a 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -30,7 +30,7 @@
 import com.android.quickstep.SystemUiProxy
 import com.android.quickstep.TaskViewUtils
 import com.android.quickstep.views.DesktopTaskView
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
 import java.util.function.Consumer
 
 /** Manage recents related operations with desktop tasks */
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 644705b..e31b1d4 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -36,10 +36,10 @@
 import com.android.quickstep.GestureState;
 import com.android.quickstep.SystemUiProxy;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.Executor;
 
 /**
  * Controls the visibility of the workspace and the resumed / paused state when desktop mode
@@ -51,6 +51,7 @@
     private static final boolean DEBUG = false;
     private final Launcher mLauncher;
     private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
+    private final Set<TaskbarDesktopModeListener> mTaskbarDesktopModeListeners = new HashSet<>();
 
     private int mVisibleDesktopTasksCount;
     private boolean mInOverviewState;
@@ -110,6 +111,16 @@
         mDesktopVisibilityListeners.remove(listener);
     }
 
+    /** Registers a listener for Taskbar changes in Desktop Mode. */
+    public void registerTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+        mTaskbarDesktopModeListeners.add(listener);
+    }
+
+    /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+    public void unregisterTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+        mTaskbarDesktopModeListeners.remove(listener);
+    }
+
     /**
      * Sets the number of desktop windows that are visible and updates launcher visibility based on
      * it.
@@ -201,6 +212,16 @@
         DisplayController.handleInfoChangeForDesktopMode(mLauncher);
     }
 
+    private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
+        if (DEBUG) {
+            Log.d(TAG, "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding="
+                    + doesAnyTaskRequireTaskbarRounding);
+        }
+        for (TaskbarDesktopModeListener listener : mTaskbarDesktopModeListeners) {
+            listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding);
+        }
+    }
+
     /**
      * TODO: b/333533253 - Remove after flag rollout
      */
@@ -377,7 +398,29 @@
 
         @Override
         public void onStashedChanged(int displayId, boolean stashed) {
-            Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
+            Log.w(TAG, "DesktopTaskListenerImpl: onStashedChanged is deprecated");
         }
+
+        @Override
+        public void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding) {
+            MAIN_EXECUTOR.execute(() -> {
+                if (mController != null && DesktopModeStatus.useRoundedCorners()) {
+                    Log.d(TAG, "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= "
+                            + doesAnyTaskRequireTaskbarRounding);
+                    mController.notifyTaskbarDesktopModeListeners(
+                            doesAnyTaskRequireTaskbarRounding);
+                }
+            });
+        }
+    }
+
+    /** A listener for Taskbar in Desktop Mode. */
+    public interface TaskbarDesktopModeListener {
+        /**
+         * Callback for when task is resized in desktop mode.
+         *
+         * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
+         */
+        void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 46501c4..e4cc6bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -29,6 +29,7 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.LayoutUtils;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -66,6 +67,9 @@
 
     @Nullable private KeyboardQuickSwitchViewController mQuickSwitchViewController;
 
+    private boolean mHasDesktopTask = false;
+    private boolean mWasDesktopTaskFilteredOut = false;
+
     /** Initialize the controller. */
     public void init(@NonNull TaskbarControllers controllers) {
         mControllers = controllers;
@@ -126,11 +130,15 @@
                     /* updateTasks= */ false,
                     currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
                             ? 0 : currentFocusedIndex,
-                    onDesktop);
+                    onDesktop,
+                    mHasDesktopTask,
+                    mWasDesktopTaskFilteredOut);
             return;
         }
 
         mTaskListChangeId = mModel.getTasks((tasks) -> {
+            mHasDesktopTask = false;
+            mWasDesktopTaskFilteredOut = false;
             if (onDesktop) {
                 processLoadedTasksOnDesktop(tasks);
             } else {
@@ -144,7 +152,9 @@
                     /* updateTasks= */ true,
                     currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
                             ? 0 : currentFocusedIndex,
-                    onDesktop);
+                    onDesktop,
+                    mHasDesktopTask,
+                    mWasDesktopTaskFilteredOut);
         });
     }
 
@@ -152,9 +162,22 @@
         // Only store MAX_TASK tasks, from most to least recent
         Collections.reverse(tasks);
         mTasks = tasks.stream()
+                .filter(task -> !(task instanceof DesktopTask))
                 .limit(MAX_TASKS)
                 .collect(Collectors.toList());
-        mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
+
+        for (int i = 0; i < tasks.size(); i++) {
+            if (tasks.get(i) instanceof DesktopTask) {
+                mHasDesktopTask = true;
+                if (i < mTasks.size()) {
+                    mWasDesktopTaskFilteredOut = true;
+                }
+                break;
+            }
+        }
+
+        mNumHiddenTasks = Math.max(0,
+                tasks.size() - (mWasDesktopTaskFilteredOut ? 1 : 0) - MAX_TASKS);
     }
 
     private void processLoadedTasksOnDesktop(List<GroupTask> tasks) {
@@ -214,6 +237,8 @@
         pw.println(prefix + "\tisOpen=" + (mQuickSwitchViewController != null));
         pw.println(prefix + "\tmNumHiddenTasks=" + mNumHiddenTasks);
         pw.println(prefix + "\tmTaskListChangeId=" + mTaskListChangeId);
+        pw.println(prefix + "\tmHasDesktopTask=" + mHasDesktopTask);
+        pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
         pw.println(prefix + "\tmTasks=[");
         for (GroupTask task : mTasks) {
             Task task1 = task.task1;
@@ -235,10 +260,6 @@
 
     class ControllerCallbacks {
 
-        int getTaskCount() {
-            return mTasks.size() + (mNumHiddenTasks == 0 ? 0 : 1);
-        }
-
         @Nullable
         GroupTask getTaskAt(int index) {
             return index < 0 || index >= mTasks.size() ? null : mTasks.get(index);
@@ -279,5 +300,10 @@
         boolean isFirstTaskRunning() {
             return isTaskRunning(getTaskAt(0));
         }
+
+        boolean isAspectRatioSquare() {
+            return mControllers != null && LayoutUtils.isAspectRatioSquare(
+                    mControllers.taskbarActivityContext.getDeviceProfile().aspectRatio);
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 39b4f77..ce96556 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -36,22 +36,25 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
-import java.util.function.Consumer;
-
 import kotlin.Unit;
 
+import java.util.function.Consumer;
+
 /**
  * A view that displays a recent task during a keyboard quick switch.
  */
 public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
 
     private static final float THUMBNAIL_BLUR_RADIUS = 1f;
+    private static final int INVALID_BORDER_RADIUS = -1;
 
     @ColorInt private final int mBorderColor;
+    @ColorInt private final int mBorderRadius;
 
     @Nullable private BorderAnimator mBorderAnimator;
 
@@ -87,6 +90,8 @@
 
         mBorderColor = ta.getColor(
                 R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR);
+        mBorderRadius = ta.getDimensionPixelSize(
+                R.styleable.TaskView_focusBorderRadius, INVALID_BORDER_RADIUS);
         ta.recycle();
     }
 
@@ -103,8 +108,10 @@
 
         Preconditions.assertNotNull(mContent);
         mBorderAnimator = BorderAnimator.createScalingBorderAnimator(
-                /* borderRadiusPx= */ resources.getDimensionPixelSize(
-                        R.dimen.keyboard_quick_switch_task_view_radius),
+                /* borderRadiusPx= */ mBorderRadius != INVALID_BORDER_RADIUS
+                        ? mBorderRadius
+                        : resources.getDimensionPixelSize(
+                                R.dimen.keyboard_quick_switch_task_view_radius),
                 /* borderWidthPx= */ resources.getDimensionPixelSize(
                                 R.dimen.keyboard_quick_switch_border_width),
                 /* boundsBuilder= */ bounds -> {
@@ -167,6 +174,61 @@
         });
     }
 
+    protected void setThumbnailsForSplitTasks(
+            @NonNull Task task1,
+            @Nullable Task task2,
+            @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
+            @Nullable IconUpdateFunction iconUpdateFunction,
+            @Nullable SplitBounds splitBounds) {
+        setThumbnails(task1, task2, thumbnailUpdateFunction, iconUpdateFunction);
+
+        if (splitBounds == null) {
+            return;
+        }
+
+
+        final boolean isLeftRightSplit = !splitBounds.appsStackedVertically;
+        final float leftOrTopTaskPercent = isLeftRightSplit
+                ? splitBounds.leftTaskPercent : splitBounds.topTaskPercent;
+
+        ConstraintLayout.LayoutParams leftTopParams = (ConstraintLayout.LayoutParams)
+                mThumbnailView1.getLayoutParams();
+        ConstraintLayout.LayoutParams rightBottomParams = (ConstraintLayout.LayoutParams)
+                mThumbnailView2.getLayoutParams();
+
+        if (isLeftRightSplit) {
+            // Set thumbnail view ratio in left right split mode.
+            leftTopParams.width = 0; // Set width to 0dp, so it uses the constraint dimension ratio.
+            leftTopParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT;
+            leftTopParams.matchConstraintPercentWidth = leftOrTopTaskPercent;
+            leftTopParams.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
+            leftTopParams.rightToLeft = R.id.thumbnail_2;
+            mThumbnailView1.setLayoutParams(leftTopParams);
+
+            rightBottomParams.width = 0;
+            rightBottomParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT;
+            rightBottomParams.matchConstraintPercentWidth = 1 - leftOrTopTaskPercent;
+            rightBottomParams.leftToRight = R.id.thumbnail_1;
+            rightBottomParams.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
+            mThumbnailView2.setLayoutParams(rightBottomParams);
+        } else {
+            // Set thumbnail view ratio in top bottom split mode.
+            leftTopParams.height = 0;
+            leftTopParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT;
+            leftTopParams.matchConstraintPercentHeight = leftOrTopTaskPercent;
+            leftTopParams.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
+            leftTopParams.bottomToTop = R.id.thumbnail_2;
+            mThumbnailView1.setLayoutParams(leftTopParams);
+
+            rightBottomParams.height = 0;
+            rightBottomParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT;
+            rightBottomParams.matchConstraintPercentHeight = 1 - leftOrTopTaskPercent;
+            rightBottomParams.topToBottom = R.id.thumbnail_1;
+            rightBottomParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
+            mThumbnailView2.setLayoutParams(rightBottomParams);
+        }
+    }
+
     private void applyThumbnail(
             @Nullable ImageView thumbnailView,
             @Nullable Task task,
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index dbd9c73..b4102a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,14 +36,12 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.core.content.res.ResourcesCompat;
 
 import com.android.app.animation.Interpolators;
 import com.android.internal.jank.Cuj;
@@ -52,9 +50,7 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
-import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 import java.util.HashMap;
@@ -102,9 +98,13 @@
     private int mTaskViewWidth;
     private int mTaskViewHeight;
     private int mSpacing;
+    private int mSmallSpacing;
     private int mOutlineRadius;
     private boolean mIsRtl;
 
+    private int mOverviewTaskIndex = -1;
+    private int mDesktopTaskIndex = -1;
+
     @Nullable private AnimatorSet mOpenAnimation;
 
     @Nullable private KeyboardQuickSwitchViewController.ViewCallbacks mViewCallbacks;
@@ -141,6 +141,8 @@
         mTaskViewHeight = resources.getDimensionPixelSize(
                 R.dimen.keyboard_quick_switch_taskview_height);
         mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
+        mSmallSpacing = resources.getDimensionPixelSize(
+                R.dimen.keyboard_quick_switch_view_small_spacing);
         mOutlineRadius = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_radius);
         mIsRtl = Utilities.isRtl(resources);
     }
@@ -148,6 +150,7 @@
     private KeyboardQuickSwitchTaskView createAndAddTaskView(
             int index,
             boolean isFinalView,
+            boolean useSmallStartSpacing,
             @LayoutRes int resId,
             @NonNull LayoutInflater layoutInflater,
             @Nullable View previousView) {
@@ -156,7 +159,7 @@
         taskView.setId(View.generateViewId());
         taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
 
-        LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
+        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         // Create a left-to-right ordering of views (or right-to-left in RTL locales)
         if (previousView != null) {
             lp.startToEnd = previousView.getId();
@@ -166,7 +169,7 @@
         lp.topToTop = PARENT_ID;
         lp.bottomToBottom = PARENT_ID;
         // Add spacing between views
-        lp.setMarginStart(mSpacing);
+        lp.setMarginStart(useSmallStartSpacing ? mSmallSpacing : mSpacing);
         if (isFinalView) {
             // Add spacing to the end of the final view so that scrolling ends with some padding.
             lp.endToEnd = PARENT_ID;
@@ -185,7 +188,8 @@
             int numHiddenTasks,
             boolean updateTasks,
             int currentFocusIndexOverride,
-            @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
+            @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks,
+            boolean useDesktopTaskView) {
         mViewCallbacks = viewCallbacks;
         Resources resources = context.getResources();
         Resources.Theme theme = context.getTheme();
@@ -197,57 +201,64 @@
             GroupTask groupTask = groupTasks.get(i);
             KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
                     i,
-                    /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
-                    groupTask instanceof DesktopTask
-                            ? R.layout.keyboard_quick_switch_textonly_taskview
+                    /* isFinalView= */ i == tasksToDisplay - 1
+                            && numHiddenTasks == 0 && !useDesktopTaskView,
+                    /* useSmallStartSpacing= */ false,
+                    mViewCallbacks.isAspectRatioSquare()
+                            ? R.layout.keyboard_quick_switch_taskview_square
                             : R.layout.keyboard_quick_switch_taskview,
                     layoutInflater,
                     previousTaskView);
 
-            if (groupTask instanceof DesktopTask desktopTask) {
-                HashMap<String, Integer> args = new HashMap<>();
-                args.put("count", desktopTask.tasks.size());
+            final boolean firstTaskIsLeftTopTask =
+                    groupTask.mSplitBounds == null
+                            || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id
+                            || groupTask.task2 == null;
 
-                currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
-                        ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
-                currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
-                        resources.getString(R.string.quick_switch_desktop),
-                        Locale.getDefault()).format(args));
-            } else {
-                final boolean firstTaskIsLeftTopTask =
-                        groupTask.mSplitBounds == null
-                        || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
-                final Task leftTopTask = firstTaskIsLeftTopTask
-                        ? groupTask.task1 : groupTask.task2;
-                final Task rightBottomTask = firstTaskIsLeftTopTask
-                        ? groupTask.task2 : groupTask.task1;
-                currentTaskView.setThumbnails(
-                        leftTopTask,
-                        rightBottomTask,
-                        updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
-                        updateTasks ? mViewCallbacks::updateIconInBackground : null);
-            }
+            currentTaskView.setThumbnailsForSplitTasks(
+                    firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2,
+                    firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1,
+                    updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+                    updateTasks ? mViewCallbacks::updateIconInBackground : null,
+                    groupTask.mSplitBounds);
+
             previousTaskView = currentTaskView;
         }
-
         if (numHiddenTasks > 0) {
             HashMap<String, Integer> args = new HashMap<>();
             args.put("count", numHiddenTasks);
 
+            mOverviewTaskIndex = getTaskCount();
             View overviewButton = createAndAddTaskView(
-                    MAX_TASKS,
-                    /* isFinalView= */ true,
-                    R.layout.keyboard_quick_switch_textonly_taskview,
+                    mOverviewTaskIndex,
+                    /* isFinalView= */ !useDesktopTaskView,
+                    /* useSmallStartSpacing= */ false,
+                    R.layout.keyboard_quick_switch_overview_taskview,
                     layoutInflater,
                     previousTaskView);
 
-            overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
-                    ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
-            overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+            overviewButton.<TextView>findViewById(R.id.large_text).setText(
+                    String.format(Locale.getDefault(), "%d", numHiddenTasks));
+            overviewButton.<TextView>findViewById(R.id.small_text).setText(new MessageFormat(
                     resources.getString(R.string.quick_switch_overflow),
                     Locale.getDefault()).format(args));
+
+            previousTaskView = overviewButton;
         }
-        mDisplayingRecentTasks = !groupTasks.isEmpty();
+        if (useDesktopTaskView) {
+            mDesktopTaskIndex = getTaskCount();
+            View desktopButton = createAndAddTaskView(
+                    mDesktopTaskIndex,
+                    /* isFinalView= */ true,
+                    /* useSmallStartSpacing= */ numHiddenTasks > 0,
+                    R.layout.keyboard_quick_switch_desktop_taskview,
+                    layoutInflater,
+                    previousTaskView);
+
+            desktopButton.<TextView>findViewById(R.id.text).setText(
+                    resources.getString(R.string.quick_switch_desktop));
+        }
+        mDisplayingRecentTasks = !groupTasks.isEmpty() || useDesktopTaskView;
 
         getViewTreeObserver().addOnGlobalLayoutListener(
                 new ViewTreeObserver.OnGlobalLayoutListener() {
@@ -260,6 +271,14 @@
                 });
     }
 
+    int getOverviewTaskIndex() {
+        return mOverviewTaskIndex;
+    }
+
+    int getDesktopTaskIndex() {
+        return mDesktopTaskIndex;
+    }
+
     protected Animator getCloseAnimation() {
         AnimatorSet closeAnimation = new AnimatorSet();
 
@@ -370,7 +389,7 @@
                     }
                 });
                 animateFocusMove(-1, Math.min(
-                        mContent.getChildCount() - 1,
+                        getTaskCount() - 1,
                         currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
                 displayedContent.setVisibility(VISIBLE);
                 setVisibility(VISIBLE);
@@ -577,7 +596,11 @@
 
     @Nullable
     protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
-        return !mDisplayingRecentTasks || index < 0 || index >= mContent.getChildCount()
+        return !mDisplayingRecentTasks || index < 0 || index >= getTaskCount()
                 ? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
     }
+
+    public int getTaskCount() {
+        return mContent.getChildCount();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index d411ba6..40e77e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.view.KeyEvent;
@@ -28,6 +30,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.SlideInRemoteTransition;
 import com.android.systemui.shared.recents.model.Task;
@@ -56,6 +59,7 @@
     private int mCurrentFocusIndex = -1;
 
     private boolean mOnDesktop;
+    private boolean mWasDesktopTaskFilteredOut;
 
     protected KeyboardQuickSwitchViewController(
             @NonNull TaskbarControllers controllers,
@@ -77,9 +81,12 @@
             int numHiddenTasks,
             boolean updateTasks,
             int currentFocusIndexOverride,
-            boolean onDesktop) {
+            boolean onDesktop,
+            boolean hasDesktopTask,
+            boolean wasDesktopTaskFilteredOut) {
         mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
         mOnDesktop = onDesktop;
+        mWasDesktopTaskFilteredOut = wasDesktopTaskFilteredOut;
 
         mKeyboardQuickSwitchView.applyLoadPlan(
                 mOverlayContext,
@@ -87,7 +94,8 @@
                 numHiddenTasks,
                 updateTasks,
                 currentFocusIndexOverride,
-                mViewCallbacks);
+                mViewCallbacks,
+                /* useDesktopTaskView= */ !onDesktop && hasDesktopTask);
     }
 
     boolean isCloseAnimationRunning() {
@@ -136,7 +144,7 @@
         }
         // If the user quick switches too quickly, updateCurrentFocusIndex might not have run.
         return launchTaskAt(mControllerCallbacks.isFirstTaskRunning()
-                && mControllerCallbacks.getTaskCount() > 1 ? 1 : 0);
+                && mKeyboardQuickSwitchView.getTaskCount() > 1 ? 1 : 0);
     }
 
     private int launchTaskAt(int index) {
@@ -144,17 +152,11 @@
             // Ignore taps on task views and alt key unpresses while the close animation is running.
             return -1;
         }
-        // Even with a valid index, this can be null if the user tries to quick switch before the
-        // views have been added in the KeyboardQuickSwitchView.
-        GroupTask task = mControllerCallbacks.getTaskAt(index);
-        if (task == null) {
-            return mOnDesktop ? 1 : Math.max(0, index);
+        if (index == mKeyboardQuickSwitchView.getOverviewTaskIndex()) {
+            // If there is a desktop task view, then we should account for it when focusing the
+            // first hidden non-desktop task view in recents view
+            return mOnDesktop ? 1 : (mWasDesktopTaskFilteredOut ? index + 1 : index);
         }
-        if (mControllerCallbacks.isTaskRunning(task)) {
-            // Ignore attempts to run the selected task if it is already running.
-            return -1;
-        }
-
         Runnable onStartCallback = () -> InteractionJankMonitorWrapper.begin(
                 mKeyboardQuickSwitchView, Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH);
         Runnable onFinishCallback = () -> InteractionJankMonitorWrapper.end(
@@ -169,6 +171,24 @@
                 onStartCallback,
                 onFinishCallback),
                 "SlideInTransition");
+        if (index == mKeyboardQuickSwitchView.getDesktopTaskIndex()) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+                            .showDesktopApps(
+                                    mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+                                    remoteTransition));
+            return -1;
+        }
+        // Even with a valid index, this can be null if the user tries to quick switch before the
+        // views have been added in the KeyboardQuickSwitchView.
+        GroupTask task = mControllerCallbacks.getTaskAt(index);
+        if (task == null) {
+            return mOnDesktop ? 1 : Math.max(0, index);
+        }
+        if (mControllerCallbacks.isTaskRunning(task)) {
+            // Ignore attempts to run the selected task if it is already running.
+            return -1;
+        }
         mControllers.taskbarActivityContext.handleGroupTaskLaunch(
                 task,
                 remoteTransition,
@@ -195,6 +215,8 @@
         pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
         pw.println(prefix + "\tisCloseAnimationRunning=" + isCloseAnimationRunning());
         pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
+        pw.println(prefix + "\tmOnDesktop=" + mOnDesktop);
+        pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
     }
 
     class ViewCallbacks {
@@ -222,7 +244,7 @@
             boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
                     || (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && isRTL)
                     || (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !isRTL);
-            int taskCount = mControllerCallbacks.getTaskCount();
+            int taskCount = mKeyboardQuickSwitchView.getTaskCount();
             int toIndex = mCurrentFocusIndex == -1
                     // Focus the second-most recent app if possible
                     ? (taskCount > 1 ? 1 : 0)
@@ -257,5 +279,9 @@
         void updateIconInBackground(Task task, Consumer<Task> callback) {
             mControllerCallbacks.updateIconInBackground(task, callback);
         }
+
+        boolean isAspectRatioSquare() {
+            return mControllerCallbacks.isAspectRatioSquare();
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 60fb094..69da7b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -19,7 +19,6 @@
 import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
 import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
 
 import android.animation.Animator;
@@ -232,9 +231,7 @@
         LauncherState state = mLauncher.getStateManager().getState();
         boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
                 && !state.isTaskbarAlignedWithHotseat(mLauncher);
-        if ((ENABLE_SHELL_TRANSITIONS
-                && isVisible
-                && (nonInteractiveState || mSkipLauncherVisibilityChange))) {
+        if (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
             return null;
         }
 
@@ -248,7 +245,7 @@
         }
 
         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
-        if (fromInit) {
+        if (fromInit || mControllers == null) {
             duration = 0;
         }
         return mTaskbarLauncherStateController.applyState(duration, startAnimation);
@@ -289,7 +286,12 @@
     }
 
     public boolean isDraggingItem() {
-        return mControllers.taskbarDragController.isDragging();
+        boolean bubblesDragging = false;
+        if (mControllers.bubbleControllers.isPresent()) {
+            bubblesDragging =
+                    mControllers.bubbleControllers.get().bubbleDragController.isDragging();
+        }
+        return mControllers.taskbarDragController.isDragging() || bubblesDragging;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f61840a..a979d58 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -63,7 +63,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Region.Op;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
 import android.graphics.drawable.RotateDrawable;
@@ -74,8 +73,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
-import android.view.View.OnClickListener;
-import android.view.View.OnHoverListener;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
@@ -106,7 +103,6 @@
 import com.android.systemui.shared.navigationbar.KeyButtonRipple;
 import com.android.systemui.shared.rotation.FloatingRotationButton;
 import com.android.systemui.shared.rotation.RotationButton;
-import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.shared.statusbar.phone.BarTransitions;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -304,8 +300,13 @@
                         .get(ALPHA_INDEX_SMALL_SCREEN),
                 flags -> (flags & FLAG_SMALL_SCREEN) == 0));
 
-        mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
-                .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+        if (!mContext.isPhoneMode()) {
+            mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+                    .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+        }
+
+        // Start at 1 because relevant flags are unset at init.
+        mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
 
         // Force nav buttons (specifically back button) to be visible during setup wizard.
         boolean isInSetup = !mContext.isUserSetupComplete();
@@ -317,39 +318,41 @@
         // - IME is showing (add separate translation for IME)
         // - VoiceInteractionWindow (assistant) is showing
         // - Keyboard shortcuts helper is showing
-        int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
-                | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
-        mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
-                flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
-                1, 0));
-        // Center nav buttons in new height for IME.
-        float transForIme = (mContext.getDeviceProfile().taskbarHeight
-                - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
-        // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
-        float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
-        mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
-                flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
-                transForIme, defaultButtonTransY));
+        if (!mContext.isPhoneMode()) {
+            int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
+                    | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
+            mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
+                    flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+                    1, 0));
+            // Center nav buttons in new height for IME.
+            float transForIme = (mContext.getDeviceProfile().taskbarHeight
+                    - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
+            // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+            float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+            mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+                    flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
+                    transForIme, defaultButtonTransY));
 
-        // Start at 1 because relevant flags are unset at init.
-        mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
-        mPropertyHolders.add(new StatePropertyHolder(
-                mOnBackgroundNavButtonColorOverrideMultiplier,
-                flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
+            mPropertyHolders.add(new StatePropertyHolder(
+                    mOnBackgroundNavButtonColorOverrideMultiplier,
+                    flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
 
-        mPropertyHolders.add(new StatePropertyHolder(
-                mSlideInViewVisibleNavButtonColorOverride,
-                flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+            mPropertyHolders.add(new StatePropertyHolder(
+                    mSlideInViewVisibleNavButtonColorOverride,
+                    flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+        }
 
         if (alwaysShowButtons) {
             initButtons(mNavButtonContainer, mEndContextualContainer,
                     mControllers.navButtonController);
             updateButtonLayoutSpacing();
-            updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneButtonNavMode());
+            updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneMode());
 
-            mPropertyHolders.add(new StatePropertyHolder(
-                    mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
-                    flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+            if (!mContext.isPhoneMode()) {
+                mPropertyHolders.add(new StatePropertyHolder(
+                        mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
+                        flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+            }
         } else if (!mIsImeRenderingNavButtons) {
             View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
                     mStartContextualContainer, mControllers.navButtonController, R.id.back);
@@ -711,7 +714,7 @@
     private void applyState() {
         int count = mPropertyHolders.size();
         for (int i = 0; i < count; i++) {
-            mPropertyHolders.get(i).setState(mState);
+            mPropertyHolders.get(i).setState(mState, mContext.isGestureNav());
         }
     }
 
@@ -1177,83 +1180,6 @@
         }
     }
 
-    private class RotationButtonImpl implements RotationButton {
-
-        private final ImageView mButton;
-        private AnimatedVectorDrawable mImageDrawable;
-
-        RotationButtonImpl(ImageView button) {
-            mButton = button;
-        }
-
-        @Override
-        public void setRotationButtonController(RotationButtonController rotationButtonController) {
-            // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
-            mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
-                    .getDrawable(rotationButtonController.getIconResId());
-            mButton.setImageDrawable(mImageDrawable);
-            mButton.setContentDescription(mButton.getResources()
-                    .getString(R.string.accessibility_rotate_button));
-            mImageDrawable.setCallback(mButton);
-        }
-
-        @Override
-        public View getCurrentView() {
-            return mButton;
-        }
-
-        @Override
-        public boolean show() {
-            mButton.setVisibility(View.VISIBLE);
-            mState |= FLAG_ROTATION_BUTTON_VISIBLE;
-            applyState();
-            return true;
-        }
-
-        @Override
-        public boolean hide() {
-            mButton.setVisibility(View.GONE);
-            mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
-            applyState();
-            return true;
-        }
-
-        @Override
-        public boolean isVisible() {
-            return mButton.getVisibility() == View.VISIBLE;
-        }
-
-        @Override
-        public void updateIcon(int lightIconColor, int darkIconColor) {
-            // TODO(b/187754252): UI Polish
-        }
-
-        @Override
-        public void setOnClickListener(OnClickListener onClickListener) {
-            mButton.setOnClickListener(onClickListener);
-        }
-
-        @Override
-        public void setOnHoverListener(OnHoverListener onHoverListener) {
-            mButton.setOnHoverListener(onHoverListener);
-        }
-
-        @Override
-        public AnimatedVectorDrawable getImageDrawable() {
-            return mImageDrawable;
-        }
-
-        @Override
-        public void setDarkIntensity(float darkIntensity) {
-            // TODO(b/187754252) UI polish
-        }
-
-        @Override
-        public boolean acceptRotationProposal() {
-            return mButton.isAttachedToWindow();
-        }
-    }
-
     private static class StatePropertyHolder {
 
         private final float mEnabledValue, mDisabledValue;
@@ -1284,13 +1210,16 @@
             mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
         }
 
-        public void setState(int flags) {
+        public void setState(int flags, boolean skipAnimation) {
             boolean isEnabled = mEnableCondition.test(flags);
             if (mIsEnabled != isEnabled) {
                 mIsEnabled = isEnabled;
                 mAnimator.cancel();
                 mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
                 mAnimator.start();
+                if (skipAnimation) {
+                    mAnimator.end();
+                }
             }
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
index 94e2244..caf3320 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -47,6 +47,7 @@
     private final int[] mTmpArr = new int[2];
 
     private @Nullable ObjectAnimator mColorChangeAnim;
+    private Boolean mIsRegionDark;
 
     public StashedHandleView(Context context) {
         this(context, null);
@@ -95,7 +96,11 @@
      * @param animate Whether to animate the change, or apply it immediately.
      */
     public void updateHandleColor(boolean isRegionDark, boolean animate) {
+        if (mIsRegionDark != null && mIsRegionDark == isRegionDark) {
+            return;
+        }
         int newColor = isRegionDark ? mStashedHandleLightColor : mStashedHandleDarkColor;
+        mIsRegionDark = isRegionDark;
         if (mColorChangeAnim != null) {
             mColorChangeAnim.cancel();
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 475b516..ec710c5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -41,8 +41,8 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.NavHandle;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
 
 import java.io.PrintWriter;
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index cd1eea2..5f733b0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,7 +29,6 @@
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
-import static com.android.launcher3.Flags.enableTaskbarCustomization;
 import static com.android.launcher3.Utilities.calculateTextHeight;
 import static com.android.launcher3.Utilities.isRunningInTestHarness;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -186,6 +185,7 @@
     private final WindowManager mWindowManager;
     private DeviceProfile mDeviceProfile;
     private WindowManager.LayoutParams mWindowLayoutParams;
+    private WindowManager.LayoutParams mLastUpdatedLayoutParams;
     private boolean mIsFullscreen;
     // The size we should return to when we call setTaskbarWindowFullscreen(false)
     private int mLastRequestedNonFullscreenSize;
@@ -229,15 +229,12 @@
         mNavigationBarPanelContext = navigationBarPanelContext;
         applyDeviceProfile(launcherDp);
         final Resources resources = getResources();
-
-        if (enableTaskbarCustomization()) {
-            mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
-            mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
-                    this,
-                    mTaskbarFeatureEvaluator,
-                    mDeviceProfile.inv.numRows,
-                    mDeviceProfile.inv.numColumns);
-        }
+        mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
+        mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
+                this,
+                mTaskbarFeatureEvaluator,
+                mDeviceProfile.inv.numRows,
+                mDeviceProfile.inv.numColumns);
 
         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
@@ -286,7 +283,7 @@
             TaskbarHotseatDimensionsProvider dimensionsProvider =
                     new DeviceProfileDimensionsProviderAdapter(this);
             BubbleStashController bubbleStashController = isTransientTaskbar
-                    ? new TransientBubbleStashController(dimensionsProvider, getResources())
+                    ? new TransientBubbleStashController(dimensionsProvider, this)
                     : new PersistentBubbleStashController(dimensionsProvider);
             bubbleControllersOptional = Optional.of(new BubbleControllers(
                     new BubbleBarController(this, bubbleBarView),
@@ -347,8 +344,9 @@
                 new KeyboardQuickSwitchController(),
                 new TaskbarPinningController(this, () ->
                         DisplayController.isInDesktopMode(this)),
-                bubbleControllersOptional);
-
+                bubbleControllersOptional,
+                new TaskbarDesktopModeController(
+                        LauncherActivityInterface.INSTANCE::getDesktopVisibilityController));
         mLauncherPrefs = LauncherPrefs.get(this);
     }
 
@@ -442,6 +440,7 @@
         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
         mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
         mWindowLayoutParams = createAllWindowParams();
+        mLastUpdatedLayoutParams = new WindowManager.LayoutParams();
 
         // Initialize controllers after all are constructed.
         mControllers.init(sharedState);
@@ -502,6 +501,15 @@
     }
 
     /**
+     * Returns {@code true} iff bubble bar is enabled (but not necessarily visible /
+     * containing bubbles).
+     */
+    @Override
+    public boolean isBubbleBarEnabled() {
+        return getBubbleControllers() != null && BubbleBarController.isBubbleBarEnabled();
+    }
+
+    /**
      * Returns if software keyboard is docked or input toolbar is placed at the taskbar area
      */
     public boolean isImeDocked() {
@@ -1423,7 +1431,7 @@
                                 && !(foundTaskView instanceof DesktopTaskView)) {
                             TestLogging.recordEvent(
                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
-                            foundTaskView.launchTasks();
+                            foundTaskView.launchWithAnimation();
                             return;
                         }
                     }
@@ -1718,6 +1726,12 @@
 
     void notifyUpdateLayoutParams() {
         if (mDragLayer.isAttachedToWindow()) {
+            // Copy the current windowLayoutParams to mLastUpdatedLayoutParams and compare the diff.
+            // If there is no change, we will skip the call to updateViewLayout.
+            int changes = mLastUpdatedLayoutParams.copyFrom(mWindowLayoutParams);
+            if (changes == 0) {
+                return;
+            }
             if (enableTaskbarNoRecreate()) {
                 mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
             } else {
@@ -1743,12 +1757,10 @@
         return mControllers.taskbarStashController.isInStashedLauncherState();
     }
 
-    @Nullable
     public TaskbarFeatureEvaluator getTaskbarFeatureEvaluator() {
         return mTaskbarFeatureEvaluator;
     }
 
-    @Nullable
     public TaskbarSpecsEvaluator getTaskbarSpecsEvaluator() {
         return mTaskbarSpecsEvaluator;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ee64060..4ac7514 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -24,6 +24,7 @@
 import android.graphics.Rect
 import android.graphics.RectF
 import com.android.app.animation.Interpolators
+import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.mapRange
@@ -70,8 +71,8 @@
     private var keyShadowDistance = 0f
     private var bottomMargin = 0
 
-    private val fullCornerRadius = context.cornerRadius.toFloat()
-    private var cornerRadius = fullCornerRadius
+    private val fullCornerRadius: Float
+    private var cornerRadius = 0f
     private var widthInsetPercentage = 0f
     private val square = Path()
     private val circle = Path()
@@ -101,7 +102,14 @@
             shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
         }
 
-        setCornerRoundness(DEFAULT_ROUNDNESS)
+        if (DisplayController.isInDesktopMode(context)) {
+            fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+            cornerRadius = fullCornerRadius
+        } else {
+            fullCornerRadius = context.cornerRadius.toFloat()
+            cornerRadius = fullCornerRadius
+            setCornerRoundness(MAX_ROUNDNESS)
+        }
     }
 
     fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
@@ -273,7 +281,7 @@
     }
 
     companion object {
-        const val DEFAULT_ROUNDNESS = 1f
+        const val MAX_ROUNDNESS = 1f
         private const val DARK_THEME_STROKE_ALPHA = 51
         private const val LIGHT_THEME_STROKE_ALPHA = 41
         private const val DARK_THEME_SHADOW_ALPHA = 51f
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d94d9175..34ab9f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
+import com.android.launcher3.util.DisplayController;
 import com.android.systemui.shared.rotation.RotationButtonController;
 
 import java.io.PrintWriter;
@@ -64,6 +65,7 @@
     public final KeyboardQuickSwitchController keyboardQuickSwitchController;
     public final TaskbarPinningController taskbarPinningController;
     public final Optional<BubbleControllers> bubbleControllers;
+    public final TaskbarDesktopModeController taskbarDesktopModeController;
 
     @Nullable private LoggableTaskbarController[] mControllersToLog = null;
     @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -111,7 +113,8 @@
             TaskbarEduTooltipController taskbarEduTooltipController,
             KeyboardQuickSwitchController keyboardQuickSwitchController,
             TaskbarPinningController taskbarPinningController,
-            Optional<BubbleControllers> bubbleControllers) {
+            Optional<BubbleControllers> bubbleControllers,
+            TaskbarDesktopModeController taskbarDesktopModeController) {
         this.taskbarActivityContext = taskbarActivityContext;
         this.taskbarDragController = taskbarDragController;
         this.navButtonController = navButtonController;
@@ -138,6 +141,7 @@
         this.keyboardQuickSwitchController = keyboardQuickSwitchController;
         this.taskbarPinningController = taskbarPinningController;
         this.bubbleControllers = bubbleControllers;
+        this.taskbarDesktopModeController = taskbarDesktopModeController;
     }
 
     /**
@@ -173,6 +177,7 @@
         taskbarEduTooltipController.init(this);
         keyboardQuickSwitchController.init(this);
         taskbarPinningController.init(this, mSharedState);
+        taskbarDesktopModeController.init(this, mSharedState);
 
         mControllersToLog = new LoggableTaskbarController[] {
                 taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -188,7 +193,13 @@
                 taskbarDragLayerController, taskbarScrimViewController,
                 voiceInteractionWindowController
         };
-        mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS);
+
+        if (DisplayController.isInDesktopMode(taskbarActivityContext)) {
+            mCornerRoundness.updateValue(taskbarDesktopModeController.getTaskbarCornerRoundness(
+                    mSharedState.showCornerRadiusInDesktopMode));
+        } else {
+            mCornerRoundness.updateValue(TaskbarBackgroundRenderer.MAX_ROUNDNESS);
+        }
 
         mAreAllControllersInitialized = true;
         for (Runnable postInitCallback : mPostInitCallbacks) {
@@ -248,6 +259,7 @@
         keyboardQuickSwitchController.onDestroy();
         taskbarStashController.onDestroy();
         bubbleControllers.ifPresent(controllers -> controllers.onDestroy());
+        taskbarDesktopModeController.onDestroy();
 
         mControllersToLog = null;
         mBackgroundRendererControllers = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
new file mode 100644
index 0000000..a376531
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 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.taskbar
+
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+
+/** Handles Taskbar in Desktop Windowing mode. */
+class TaskbarDesktopModeController(
+    private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?
+) : TaskbarDesktopModeListener {
+    private lateinit var taskbarControllers: TaskbarControllers
+    private lateinit var taskbarSharedState: TaskbarSharedState
+
+    private val desktopVisibilityController: DesktopVisibilityController?
+        get() = desktopVisibilityControllerProvider()
+
+    fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) {
+        taskbarControllers = controllers
+        taskbarSharedState = sharedState
+        desktopVisibilityController?.registerTaskbarDesktopModeListener(this)
+    }
+
+    override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
+        taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding
+        val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding)
+        taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start()
+    }
+
+    fun getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding: Boolean): Float {
+        return if (doesAnyTaskRequireTaskbarRounding) {
+            MAX_ROUNDNESS
+        } else {
+            0f
+        }
+    }
+
+    fun onDestroy() = desktopVisibilityController?.unregisterTaskbarDesktopModeListener(this)
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a635537..b5a3314 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -169,8 +169,11 @@
 
     override fun addArrow() {
         super.addArrow()
+        val location = IntArray(2)
+        popupContainer.getLocationInDragLayer(dividerView, location)
+        val dividerViewX = location[0].toFloat()
         // Change arrow location to the middle of popup.
-        mArrow.x = (dividerView.x + dividerView.width / 2) - (mArrowWidth / 2)
+        mArrow.x = (dividerViewX + dividerView.width / 2) - (mArrowWidth / 2)
     }
 
     override fun updateArrowColor() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index acf976f..2845cee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -171,6 +171,10 @@
     }
 
     private void updateBackgroundAlpha() {
+        if (mActivity.isPhoneMode()) {
+            return;
+        }
+
         final float bgNavbar = mBgNavbar.value;
         final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
                 * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
index 8c7879d..3bff31f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
@@ -50,6 +50,7 @@
     private final View mHoverView;
     private final ArrowTipView mHoverToolTipView;
     private final String mToolTipText;
+    private final int mYOffset;
 
     public TaskbarHoverToolTipController(TaskbarActivityContext activity, TaskbarView taskbarView,
             View hoverView) {
@@ -79,6 +80,8 @@
         mHoverToolTipView.findViewById(R.id.text).setPadding(horizontalPadding, verticalPadding,
                 horizontalPadding, verticalPadding);
         mHoverToolTipView.setAlpha(0);
+        mYOffset = arrowContextWrapper.getResources().getDimensionPixelSize(
+                R.dimen.taskbar_tooltip_y_offset);
 
         AnimatorSet hoverOpenAnimator = new AnimatorSet();
         ObjectAnimator alphaOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0f, 1f);
@@ -89,7 +92,7 @@
         mHoverToolTipView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     mHoverToolTipView.setPivotY(bottom);
-                    mHoverToolTipView.setY(mTaskbarView.getTop() - (bottom - top));
+                    mHoverToolTipView.setY(mTaskbarView.getTop() - mYOffset - (bottom - top));
                 });
     }
 
@@ -121,6 +124,6 @@
         }
         Rect iconViewBounds = Utilities.getViewBounds(mHoverView);
         mHoverToolTipView.showAtLocation(mToolTipText, iconViewBounds.centerX(),
-                mTaskbarView.getTop(), /* shouldAutoClose= */ false);
+                mTaskbarView.getTop() - mYOffset, /* shouldAutoClose= */ false);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index ff1ea98..221504d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -56,7 +56,6 @@
 import com.android.launcher3.util.Executors
 import java.io.PrintWriter
 import kotlin.jvm.optionals.getOrNull
-import kotlin.math.max
 
 /** Handles the insets that Taskbar provides to underlying apps and the IME. */
 class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -106,7 +105,8 @@
     }
 
     fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() {
-        val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+        val taskbarStashController = controllers.taskbarStashController
+        val tappableHeight = taskbarStashController.tappableHeightToReportToApps
         // We only report tappableElement height for unstashed, persistent taskbar,
         // which is also when we draw the rounded corners above taskbar.
         val insetsRoundedCornerFlag =
@@ -133,7 +133,7 @@
         }
 
         val bubbleControllers = controllers.bubbleControllers.getOrNull()
-        val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
+        val taskbarTouchableHeight = taskbarStashController.touchableHeight
         val bubblesTouchableHeight =
             bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
         // reset touch bounds
@@ -147,12 +147,10 @@
                 defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
             }
         }
-        val taskbarUIController = controllers.uiController as? LauncherTaskbarUIController
-        if (taskbarUIController?.isOnHome != true) {
-            // only add the bars touch region if not on home
-            val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
+        if (taskbarStashController.isInApp || taskbarStashController.isInOverview) {
+            // only add the taskbar touch region if not on home
             val bottom = windowLayoutParams.height
-            val top = bottom - touchableHeight
+            val top = bottom - taskbarTouchableHeight
             val right = context.deviceProfile.widthPx
             defaultTouchableRegion.addBoundsToRegion(Rect(/* left= */ 0, top, right, bottom))
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 5c3add2..4188a0f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
 import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE;
@@ -47,6 +48,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.RecentsAnimationController;
@@ -146,6 +148,7 @@
     private MultiProperty mIconAlphaForHome;
     private QuickstepLauncher mLauncher;
 
+    private boolean mIsDestroyed = false;
     private Integer mPrevState;
     private int mState;
     private LauncherState mLauncherState = LauncherState.NORMAL;
@@ -244,7 +247,9 @@
 
         resetIconAlignment();
 
-        mLauncher.getStateManager().addStateListener(mStateListener);
+        if (!mControllers.taskbarActivityContext.isPhoneMode()) {
+            mLauncher.getStateManager().addStateListener(mStateListener);
+        }
         mLauncherState = launcher.getStateManager().getState();
         updateStateForSysuiFlags(sysuiStateFlags, /*applyState*/ false);
 
@@ -256,6 +261,7 @@
     }
 
     public void onDestroy() {
+        mIsDestroyed = true;
         mCanSyncViews = false;
 
         mIconAlignment.finishAnimation();
@@ -349,8 +355,10 @@
         // interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
         // when the device is asleep, the second condition extends ensures that the transition from
         // and to the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar
-        // hide/reveal animation timings.
-        boolean isTaskbarHidden = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+        // hide/reveal animation timings. The Taskbar can show when dreaming if the glanceable hub
+        // is showing on top.
+        boolean isTaskbarHidden = (hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+                && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_COMMUNAL_HUB_SHOWING))
                 || (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_AWAKE;
         updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden);
 
@@ -407,7 +415,7 @@
     }
 
     public Animator applyState(long duration, boolean start) {
-        if (mControllers.taskbarActivityContext.isDestroyed()) {
+        if (mIsDestroyed || mControllers.taskbarActivityContext.isPhoneMode()) {
             return null;
         }
         Animator animator = null;
@@ -455,7 +463,8 @@
             controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview);
         });
 
-        mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_OVERVIEW,
+        TaskbarStashController stashController = mControllers.taskbarStashController;
+        stashController.updateStateForFlag(FLAG_IN_OVERVIEW,
                 mLauncherState == LauncherState.OVERVIEW);
 
         AnimatorSet animatorSet = new AnimatorSet();
@@ -487,8 +496,6 @@
                 public void onAnimationStart(Animator animation) {
                     mIsAnimatingToLauncher = isInLauncher;
 
-                    TaskbarStashController stashController =
-                            mControllers.taskbarStashController;
                     if (DEBUG) {
                         Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !isInLauncher);
                     }
@@ -504,6 +511,8 @@
 
             // Handle closing open popups when going home/overview
             handleOpenFloatingViews = true;
+        } else {
+            stashController.applyState();
         }
 
         if (handleOpenFloatingViews && isInLauncher) {
@@ -584,6 +593,12 @@
 
         float cornerRoundness = isInLauncher ? 0 : 1;
 
+        if (DisplayController.isInDesktopMode(mLauncher) && mControllers.getSharedState() != null) {
+            cornerRoundness =
+                    mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness(
+                            mControllers.getSharedState().showCornerRadiusInDesktopMode);
+        }
+
         // Don't animate if corner roundness has reached desired value.
         if (mTaskbarCornerRoundness.isAnimating()
                 || mTaskbarCornerRoundness.value != cornerRoundness) {
@@ -753,7 +768,7 @@
     }
 
     private void updateIconAlphaForHome(float alpha) {
-        if (mControllers.taskbarActivityContext.isDestroyed()) {
+        if (mIsDestroyed) {
             return;
         }
         mIconAlphaForHome.setValue(alpha);
@@ -856,7 +871,8 @@
                 "%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value));
         pw.println(String.format(
                 "%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue()));
-        pw.println(String.format("%s\tmPrevState=%s", prefix, getStateString(mPrevState)));
+        pw.println(String.format("%s\tmPrevState=%s", prefix,
+                mPrevState == null ? null : getStateString(mPrevState)));
         pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState)));
         pw.println(String.format("%s\tmLauncherState=%s", prefix, mLauncherState));
         pw.println(String.format(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index f411e79..8c87fa6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -459,10 +459,12 @@
                 + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
                 + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
                 + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
-            if (!isTaskbarEnabled) {
+            if (!isTaskbarEnabled || !isLargeScreenTaskbar) {
                 SystemUiProxy.INSTANCE.get(mContext)
                     .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
-                return;
+                if (!isTaskbarEnabled) {
+                    return;
+                }
             }
 
             if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 4df0223..2370dfd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -21,7 +21,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
-import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
+import static com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
 
 import android.animation.ObjectAnimator;
 import android.view.animation.Interpolator;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 77bd35f..729cbe9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -102,5 +102,8 @@
 
     // To track if taskbar was stashed / unstashed between configuration changes (which recreates
     // the task bar).
-    public Boolean taskbarWasStashedAuto = true;
+    public boolean taskbarWasStashedAuto = true;
+
+    // should show corner radius on persistent taskbar when in desktop mode.
+    public boolean showCornerRadiusInDesktopMode = false;
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 8a20131..d07b011 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -152,12 +152,12 @@
     /**
      * How long to delay the icon/stash handle alpha.
      */
-    private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
+    public static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
 
     /**
      * How long the icon/stash handle alpha animation plays.
      */
-    private static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+    public static final long TASKBAR_STASH_ALPHA_DURATION = 50;
 
     /**
      * How long to delay the icon/stash handle alpha for the home to app taskbar animation.
@@ -424,6 +424,11 @@
         return hasAnyFlag(FLAGS_IN_APP);
     }
 
+    /** Returns whether the taskbar is currently in overview screen. */
+    public boolean isInOverview() {
+        return hasAnyFlag(FLAG_IN_OVERVIEW);
+    }
+
     /**
      * Returns the height that taskbar will be touchable.
      */
@@ -1132,6 +1137,10 @@
                     TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
                     !hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
         }
+        if (hasAnyFlag(changedFlags, FLAG_IN_OVERVIEW | FLAG_IN_APP)) {
+            mControllers.runAfterInit(() -> mControllers.taskbarInsetsController
+                    .onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
+        }
         mActivity.applyForciblyShownFlagWhileTransientTaskbarUnstashed(!isStashedInApp());
     }
 
@@ -1146,7 +1155,8 @@
      */
     public void setUpTaskbarSystemAction(boolean visible) {
         UI_HELPER_EXECUTOR.execute(() -> {
-            if (!visible || !DisplayController.isTransientTaskbar(mActivity)) {
+            if (!visible || !DisplayController.isTransientTaskbar(mActivity)
+                    || mActivity.isPhoneMode()) {
                 mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR);
                 mIsTaskbarSystemActionRegistered = false;
                 return;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 43960a1..6b1173a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -20,7 +20,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_HIDE;
 
 import android.content.Intent;
 import android.graphics.drawable.BitmapDrawable;
@@ -40,6 +39,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
@@ -394,7 +394,7 @@
         if (overviewCommandHelper == null) {
             return;
         }
-        overviewCommandHelper.addCommand(TYPE_HIDE);
+        overviewCommandHelper.addCommand(CommandType.HIDE);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index fc76972..32d6561 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -22,10 +22,8 @@
 import static com.android.launcher3.Flags.enableRecentsInTaskbar;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -39,12 +37,9 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 
-import androidx.annotation.DimenRes;
-import androidx.annotation.DrawableRes;
 import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -62,17 +57,16 @@
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.taskbar.customization.TaskbarAllAppsButtonContainer;
+import com.android.launcher3.taskbar.customization.TaskbarDividerContainer;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconButtonView;
-import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.util.AssistStateManager;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 
 import java.util.List;
 import java.util.function.Predicate;
@@ -100,16 +94,19 @@
     private View.OnLongClickListener mIconLongClickListener;
 
     // Only non-null when the corresponding Folder is open.
-    private @Nullable FolderIcon mLeaveBehindFolderIcon;
+    @Nullable private FolderIcon mLeaveBehindFolderIcon;
 
     // Only non-null when device supports having an All Apps button.
-    private @Nullable IconButtonView mAllAppsButton;
-    private Runnable mAllAppsTouchRunnable;
-    private long mAllAppsButtonTouchDelayMs;
-    private boolean mAllAppsTouchTriggered;
+    @Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
 
     // Only non-null when device supports having an All Apps button.
-    private @Nullable IconButtonView mTaskbarDivider;
+    @Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
+
+    /**
+     * Whether the divider is between Hotseat icons and Recents,
+     * instead of between All Apps button and Hotseat.
+     */
+    private boolean mAddedDividerForRecents;
 
     private final View mQsb;
 
@@ -167,55 +164,14 @@
         // Needed to draw folder leave-behind when opening one.
         setWillNotDraw(false);
 
-        mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
-                .inflate(R.layout.taskbar_all_apps_button, this, false);
-        mAllAppsButton.setIconDrawable(resources.getDrawable(
-                getAllAppsButton(isTransientTaskbar)));
-        mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
-        mAllAppsButton.setForegroundTint(
-                mActivityContext.getColor(R.color.all_apps_button_color));
+        mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
 
         if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
-            mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
-                    R.layout.taskbar_divider,
-                    this, false);
-            mTaskbarDivider.setIconDrawable(
-                    resources.getDrawable(R.drawable.taskbar_divider_button));
-            mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+            mTaskbarDividerContainer = new TaskbarDividerContainer(context);
         }
 
         // TODO: Disable touch events on QSB otherwise it can crash.
         mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
-
-        // Default long press (touch) delay = 400ms
-        mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
-    }
-
-    @DrawableRes
-    private int getAllAppsButton(boolean isTransientTaskbar) {
-        boolean shouldSelectTransientIcon =
-                (isTransientTaskbar || enableTaskbarPinning())
-                && !mActivityContext.isThreeButtonNav();
-        if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
-            return shouldSelectTransientIcon
-                    ? R.drawable.ic_transient_taskbar_all_apps_search_button
-                    : R.drawable.ic_taskbar_all_apps_search_button;
-        } else {
-            return shouldSelectTransientIcon
-                    ? R.drawable.ic_transient_taskbar_all_apps_button
-                    : R.drawable.ic_taskbar_all_apps_button;
-        }
-    }
-
-    @DimenRes
-    public int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
-        if (isTransientTaskbar) {
-            return R.dimen.transient_taskbar_all_apps_button_translation_x_offset;
-        } else {
-            return ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()
-                    ? R.dimen.taskbar_all_apps_search_button_translation_x_offset
-                    : R.dimen.taskbar_all_apps_button_translation_x_offset;
-        }
     }
 
     @Override
@@ -300,27 +256,11 @@
         mIconClickListener = mControllerCallbacks.getIconOnClickListener();
         mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
 
-        if (mAllAppsButton != null) {
-            mAllAppsButton.setOnClickListener(this::onAllAppsButtonClick);
-            mAllAppsButton.setOnLongClickListener(this::onAllAppsButtonLongClick);
-            mAllAppsButton.setOnTouchListener(this::onAllAppsButtonTouch);
-            mAllAppsButton.setHapticFeedbackEnabled(
-                    mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
-            mAllAppsTouchRunnable = () -> {
-                mControllerCallbacks.triggerAllAppsButtonLongClick();
-                mAllAppsTouchTriggered = true;
-            };
-            AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(mContext);
-            if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
-                    && assistStateManager.getLPNHDurationMillis().isPresent()) {
-                mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
-            }
+        if (mAllAppsButtonContainer != null) {
+            mAllAppsButtonContainer.setUpCallbacks(callbacks);
         }
-        if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
-            mTaskbarDivider.setOnLongClickListener(
-                    mControllerCallbacks.getTaskbarDividerLongClickListener());
-            mTaskbarDivider.setOnTouchListener(
-                    mControllerCallbacks.getTaskbarDividerRightClickListener());
+        if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
+            mTaskbarDividerContainer.setUpCallbacks(callbacks);
         }
     }
 
@@ -340,13 +280,13 @@
     protected void updateHotseatItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
         int nextViewIndex = 0;
         int numViewsAnimated = 0;
-        boolean addedDividerForRecents = false;
+        mAddedDividerForRecents = false;
 
-        if (mAllAppsButton != null) {
-            removeView(mAllAppsButton);
+        if (mAllAppsButtonContainer != null) {
+            removeView(mAllAppsButtonContainer);
 
-            if (mTaskbarDivider != null) {
-                removeView(mTaskbarDivider);
+            if (mTaskbarDividerContainer != null) {
+                removeView(mTaskbarDividerContainer);
             }
         }
         removeView(mQsb);
@@ -433,9 +373,9 @@
             nextViewIndex++;
         }
 
-        if (mTaskbarDivider != null && !recentTasks.isEmpty()) {
-            addView(mTaskbarDivider, nextViewIndex++);
-            addedDividerForRecents = true;
+        if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
+            addView(mTaskbarDividerContainer, nextViewIndex++);
+            mAddedDividerForRecents = true;
         }
 
         // Add Recent/Running icons.
@@ -498,12 +438,14 @@
             removeAndRecycle(getChildAt(nextViewIndex));
         }
 
-        if (mAllAppsButton != null) {
-            addView(mAllAppsButton, mIsRtl ? getChildCount() : 0);
+        if (mAllAppsButtonContainer != null) {
+            addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
 
             // If there are no recent tasks, add divider after All Apps (unless it's the only view).
-            if (!addedDividerForRecents && mTaskbarDivider != null && getChildCount() > 1) {
-                addView(mTaskbarDivider, mIsRtl ? (getChildCount() - 1) : 1);
+            if (!mAddedDividerForRecents
+                    && mTaskbarDividerContainer != null
+                    && getChildCount() > 1) {
+                addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
             }
         }
         if (mActivityContext.getDeviceProfile().isQsbInline) {
@@ -631,7 +573,7 @@
                 int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
                 int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
                 child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
-            } else if (child == mTaskbarDivider) {
+            } else if (child == mTaskbarDividerContainer) {
                 iconEnd += mItemMarginLeftRight;
                 int iconStart = iconEnd - mIconTouchSize;
                 child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
@@ -721,16 +663,24 @@
      * Returns the all apps button in the taskbar.
      */
     @Nullable
-    public View getAllAppsButtonView() {
-        return mAllAppsButton;
+    public TaskbarAllAppsButtonContainer getAllAppsButtonContainer() {
+        return mAllAppsButtonContainer;
     }
 
     /**
      * Returns the taskbar divider in the taskbar.
      */
     @Nullable
-    public View getTaskbarDividerView() {
-        return mTaskbarDivider;
+    public TaskbarDividerContainer getTaskbarDividerViewContainer() {
+        return mTaskbarDividerContainer;
+    }
+
+    /**
+     * Returns whether the divider is between Hotseat icons and Recents,
+     * instead of between All Apps button and Hotseat.
+     */
+    public boolean isDividerForRecents() {
+        return mAddedDividerForRecents;
     }
 
     /**
@@ -818,48 +768,6 @@
                 }
             }
         }
-        return mAllAppsButton;
-    }
-
-    private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mAllAppsTouchTriggered = false;
-                MAIN_EXECUTOR.getHandler().postDelayed(
-                        mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                cancelAllAppsButtonTouch();
-        }
-        return false;
-    }
-
-    private void cancelAllAppsButtonTouch() {
-        MAIN_EXECUTOR.getHandler().removeCallbacks(mAllAppsTouchRunnable);
-        // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
-        // the next frame, so we need to post twice and delay the reset.
-        if (mAllAppsButton != null) {
-            mAllAppsButton.post(() -> {
-                mAllAppsButton.post(() -> {
-                    mAllAppsTouchTriggered = false;
-                });
-            });
-        }
-    }
-
-    private void onAllAppsButtonClick(View view) {
-        if (!mAllAppsTouchTriggered) {
-            mControllerCallbacks.triggerAllAppsButtonClick(view);
-        }
-    }
-
-    // Handle long click from Switch Access and Voice Access
-    private boolean onAllAppsButtonLongClick(View view) {
-        if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
-                && !mAllAppsTouchTriggered) {
-            mControllerCallbacks.triggerAllAppsButtonLongClick();
-        }
-        return true;
+        return mAllAppsButtonContainer;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index e6cac2f..5ec00ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -28,7 +28,7 @@
 import com.android.internal.jank.Cuj;
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 
 /**
  * Callbacks for {@link TaskbarView} to interact with its controller.
@@ -51,7 +51,7 @@
     }
 
     /** Trigger All Apps button click action. */
-    protected void triggerAllAppsButtonClick(View v) {
+    public void triggerAllAppsButtonClick(View v) {
         InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
                 /* tag= */ "TASKBAR_BUTTON");
         mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
@@ -59,7 +59,7 @@
     }
 
     /** Trigger All Apps button long click action. */
-    protected void triggerAllAppsButtonLongClick() {
+    public void triggerAllAppsButtonLongClick() {
         mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
     }
 
@@ -74,6 +74,11 @@
         };
     }
 
+    /** Check to see if we support long press on taskbar divider */
+    public boolean supportsDividerLongPress() {
+        return !mActivity.isThreeButtonNav();
+    }
+
     public View.OnTouchListener getTaskbarDividerRightClickListener() {
         return (v, event) -> {
             if (event.isFromSource(InputDevice.SOURCE_MOUSE)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index b8b85d1..aa3e6bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -72,7 +72,6 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.views.IconButtonView;
 import com.android.quickstep.util.GroupTask;
 import com.android.systemui.shared.recents.model.Task;
 
@@ -100,6 +99,12 @@
     public static final int ALPHA_INDEX_BUBBLE_BAR = 7;
     private static final int NUM_ALPHA_CHANNELS = 8;
 
+    /** Only used for animation purposes, to position the divider between two item indices. */
+    public static final float DIVIDER_VIEW_POSITION_OFFSET = 0.5f;
+
+    /** Used if an unexpected edge case is hit in {@link #getPositionInHotseat}. */
+    private static final float ERROR_POSITION_IN_HOTSEAT_NOT_FOUND = -100;
+
     private static boolean sEnableModelLoadingForTests = true;
 
     private final TaskbarActivityContext mActivity;
@@ -144,6 +149,7 @@
     private Runnable mOnControllerPreCreateCallback = NO_OP;
 
     // Stored here as signals to determine if the mIconAlignController needs to be recreated.
+    private boolean mIsIconAlignedWithHotseat;
     private boolean mIsHotseatIconOnTopWhenAligned;
     private boolean mIsStashed;
 
@@ -212,8 +218,8 @@
         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
             // This gets modified in NavbarButtonsViewController, but the initial value it reads
             // may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
-            mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
-                    .animateToValue(mActivity.isPhoneButtonNavMode() ? 0 : 1).start();
+            mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN).setValue(
+                    mActivity.isPhoneMode() ? 0 : 1);
         }
         if (enableTaskbarPinning()) {
             mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
@@ -292,7 +298,7 @@
 
     @Nullable
     public View getAllAppsButtonView() {
-        return mTaskbarView.getAllAppsButtonView();
+        return mTaskbarView.getAllAppsButtonContainer();
     }
 
     public AnimatedFloat getTaskbarIconScaleForStash() {
@@ -359,9 +365,9 @@
         View[] iconViews = mTaskbarView.getIconViews();
         float scale = mTaskbarIconTranslationXForPinning.value;
         float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
-                mTaskbarView.getAllAppsButtonTranslationXOffset(true));
+                mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(true));
         float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
-                mTaskbarView.getAllAppsButtonTranslationXOffset(false));
+                mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(false));
 
         float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
                 persistentTaskbarAllAppsOffset);
@@ -376,7 +382,7 @@
         }
 
         if (mActivity.isThreeButtonNav()) {
-            ((IconButtonView) mTaskbarView.getAllAppsButtonView())
+            mTaskbarView.getAllAppsButtonContainer()
                     .setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
             return;
         }
@@ -401,8 +407,8 @@
                         -finalMarginScale * (iconIndex - halfIconCount));
             }
 
-            if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
-                ((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
+            if (iconView.equals(mTaskbarView.getAllAppsButtonContainer())) {
+                mTaskbarView.getAllAppsButtonContainer().setTranslationXForTaskbarAllAppsIcon(
                         allAppIconTranslateRange);
             }
         }
@@ -530,7 +536,7 @@
     }
 
     public View getTaskbarDividerView() {
-        return mTaskbarView.getTaskbarDividerView();
+        return mTaskbarView.getTaskbarDividerViewContainer();
     }
 
     /**
@@ -681,15 +687,17 @@
             mIconAlignControllerLazy = null;
             return;
         }
-
         boolean isHotseatIconOnTopWhenAligned =
                 mControllers.uiController.isHotseatIconOnTopWhenAligned();
+        boolean isIconAlignedWithHotseat = mControllers.uiController.isIconAlignedWithHotseat();
         boolean isStashed = mControllers.taskbarStashController.isStashed();
-        // Re-create animation when mIsHotseatIconOnTopWhenAligned or mIsStashed changes.
+        // Re-create animation when any of these values change.
         if (mIconAlignControllerLazy == null
                 || mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned
+                || mIsIconAlignedWithHotseat != isIconAlignedWithHotseat
                 || mIsStashed != isStashed) {
             mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
+            mIsIconAlignedWithHotseat = isIconAlignedWithHotseat;
             mIsStashed = isStashed;
             mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
         }
@@ -741,17 +749,22 @@
                 ? mTransientTaskbarDp.taskbarBottomMargin
                 : mPersistentTaskbarDp.taskbarBottomMargin;
 
+        int firstRecentTaskIndex = -1;
         for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
             View child = mTaskbarView.getChildAt(i);
-            boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
-            boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerView();
+            boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
+            boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
+            boolean isRecentTask = child.getTag() instanceof GroupTask;
+            // TODO(b/343522351): show recents on the home screen.
+            final boolean isRecentsInHotseat = false;
             if (!mIsHotseatIconOnTopWhenAligned) {
                 // When going to home, the EMPHASIZED interpolator in TaskbarLauncherStateController
                 // plays iconAlignment to 1 really fast, therefore moving the fading towards the end
                 // to avoid icons disappearing rather than fading out visually.
                 setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
             } else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())
-                    || (isTaskbarDividerView && enableTaskbarPinning())) {
+                    || (isTaskbarDividerView && enableTaskbarPinning())
+                    || (isRecentTask && !isRecentsInHotseat)) {
                 if (!isToHome
                         && mIsHotseatIconOnTopWhenAligned
                         && mIsStashed) {
@@ -812,25 +825,17 @@
                 continue;
             }
 
-            float positionInHotseat;
-            if (isAllAppsButton) {
-                // Note that there is no All Apps button in the hotseat,
-                // this position is only used as its convenient for animation purposes.
-                positionInHotseat = Utilities.isRtl(child.getResources())
-                        ? taskbarDp.numShownHotseatIcons
-                        : -1;
-            }  else if (isTaskbarDividerView) {
-                // Note that there is no taskbar divider view in the hotseat,
-                // this position is only used as its convenient for animation purposes.
-                positionInHotseat = Utilities.isRtl(child.getResources())
-                        ? taskbarDp.numShownHotseatIcons - 0.5f
-                        : -0.5f;
-            } else if (child.getTag() instanceof ItemInfo) {
-                positionInHotseat = ((ItemInfo) child.getTag()).screenId;
-            } else {
-                Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
-                continue;
+            int recentTaskIndex = -1;
+            if (isRecentTask) {
+                if (firstRecentTaskIndex < 0) {
+                    firstRecentTaskIndex = i;
+                }
+                recentTaskIndex = i - firstRecentTaskIndex;
             }
+            float positionInHotseat = getPositionInHotseat(taskbarDp.numShownHotseatIcons, child,
+                    mIsRtl, isAllAppsButton, isTaskbarDividerView,
+                    mTaskbarView.isDividerForRecents(), recentTaskIndex);
+            if (positionInHotseat == ERROR_POSITION_IN_HOTSEAT_NOT_FOUND) continue;
 
             float hotseatAdjustedBorderSpace =
                     launcherDp.getHotseatAdjustedBorderSpaceForBubbleBar(child.getContext());
@@ -866,6 +871,58 @@
         return controller;
     }
 
+    /**
+     * Returns the index of the given child relative to its position in hotseat.
+     * Examples:
+     * -1 is the item before the first hotseat item.
+     * -0.5 is between those (e.g. for the divider).
+     * {@link #ERROR_POSITION_IN_HOTSEAT_NOT_FOUND} if there's no calculation relative to hotseat.
+     */
+    @VisibleForTesting
+    float getPositionInHotseat(int numShownHotseatIcons, View child, boolean isRtl,
+            boolean isAllAppsButton, boolean isTaskbarDividerView, boolean isDividerForRecents,
+            int recentTaskIndex) {
+        float positionInHotseat;
+        // Note that there is no All Apps button in the hotseat,
+        // this position is only used as it's convenient for animation purposes.
+        float allAppsButtonPositionInHotseat = isRtl
+                // Right after all hotseat items.
+                // [HHHHHH]|[>A<]
+                ? numShownHotseatIcons
+                // Right before all hotseat items.
+                // [>A<]|[HHHHHH]
+                : -1;
+        // Note that there are no recent tasks in the hotseat,
+        // this position is only used as it's convenient for animation purposes.
+        float firstRecentTaskPositionInHotseat = isRtl
+                // After all hotseat icons and All Apps button.
+                // [HHHHHH][A]|[>R<R]
+                ? numShownHotseatIcons + 1
+                // Right after all hotseat items.
+                // [A][HHHHHH]|[>R<R]
+                : numShownHotseatIcons;
+        if (isAllAppsButton) {
+            positionInHotseat = allAppsButtonPositionInHotseat;
+        }  else if (isTaskbarDividerView) {
+            // Note that there is no taskbar divider view in the hotseat,
+            // this position is only used as it's convenient for animation purposes.
+            float relativePosition = isDividerForRecents
+                    ? firstRecentTaskPositionInHotseat
+                    : allAppsButtonPositionInHotseat;
+            positionInHotseat = relativePosition > 0
+                    ? relativePosition - DIVIDER_VIEW_POSITION_OFFSET
+                    : relativePosition + DIVIDER_VIEW_POSITION_OFFSET;
+        } else if (child.getTag() instanceof ItemInfo) {
+            positionInHotseat = ((ItemInfo) child.getTag()).screenId;
+        } else if (recentTaskIndex >= 0) {
+            positionInHotseat = firstRecentTaskPositionInHotseat + recentTaskIndex;
+        } else {
+            Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
+            return ERROR_POSITION_IN_HOTSEAT_NOT_FOUND;
+        }
+        return positionInHotseat;
+    }
+
     private boolean bubbleBarHasBubbles() {
         return mControllers.bubbleControllers.isPresent()
                 && mControllers.bubbleControllers.get().bubbleBarViewController.hasBubbles();
@@ -950,7 +1007,6 @@
                 "ALPHA_INDEX_RECENTS_DISABLED",
                 "ALPHA_INDEX_NOTIFICATION_EXPANDED",
                 "ALPHA_INDEX_ASSISTANT_INVOKED",
-                "ALPHA_INDEX_IME_BUTTON_NAV",
                 "ALPHA_INDEX_SMALL_SCREEN");
 
         mModelCallbacks.dumpLogs(prefix + "\t", pw);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 90ac872..f5ac66f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar.allapps;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
 import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
 import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
 
@@ -193,14 +192,12 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mActivityContext.addOnDeviceProfileChangeListener(this);
-        if (enablePredictiveBackGesture()) {
-            mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
-            mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
-            OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
-            if (dispatcher != null) {
-                dispatcher.registerOnBackInvokedCallback(
-                        OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
-            }
+        mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
+        mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
+        OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+        if (dispatcher != null) {
+            dispatcher.registerOnBackInvokedCallback(
+                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
         }
     }
 
@@ -208,13 +205,11 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mActivityContext.removeOnDeviceProfileChangeListener(this);
-        if (enablePredictiveBackGesture()) {
-            mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
-            mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
-            OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
-            if (dispatcher != null) {
-                dispatcher.unregisterOnBackInvokedCallback(this);
-            }
+        mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
+        mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
+        OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+        if (dispatcher != null) {
+            dispatcher.unregisterOnBackInvokedCallback(this);
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a36d5f0..d70a317 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -41,10 +41,10 @@
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 import com.android.wm.shell.Flags;
 import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
-import com.android.wm.shell.common.bubbles.RemovedBubble;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.RemovedBubble;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -496,6 +496,11 @@
                 () -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
     }
 
+    /** Notifies WMShell to show the expanded view. */
+    void showExpandedView() {
+        mSystemUiProxy.showExpandedView();
+    }
+
     //
     // Loading data for the bubbles
     //
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
index 39d1ed7..7a32ef1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
@@ -17,7 +17,7 @@
 
 import android.graphics.Bitmap
 import android.graphics.Path
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
 
 /** An entity in the bubble bar. */
 sealed class BubbleBarItem(open var key: String, open var view: BubbleView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index a6b0860..9c34307 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -28,8 +28,8 @@
 import androidx.core.view.updateLayoutParams
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BaseBubblePinController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
 
 /**
  * Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 1f0851f..06301c7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -48,7 +48,7 @@
 import com.android.launcher3.anim.SpringAnimationBuilder;
 import com.android.launcher3.taskbar.bubbles.animation.BubbleAnimator;
 import com.android.launcher3.util.DisplayController;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -244,7 +244,7 @@
                     if (mIsBarExpanded && mSelectedBubbleView != null) {
                         mSelectedBubbleView.markSeen();
                     }
-                    updateWidth();
+                    updateLayoutParams();
                 },
                 /* onUpdate= */ animator -> {
                     updateBubblesLayoutProperties(mBubbleBarLocation);
@@ -733,7 +733,7 @@
 
                 @Override
                 public void onAnimationEnd() {
-                    updateWidth();
+                    updateLayoutParams();
                     mBubbleAnimator = null;
                 }
 
@@ -791,7 +791,7 @@
             @Override
             public void onAnimationEnd() {
                 removeView(removedBubble);
-                updateWidth();
+                updateLayoutParams();
                 mBubbleAnimator = null;
                 if (onEndRunnable != null) {
                     onEndRunnable.run();
@@ -823,7 +823,7 @@
     @Override
     public void addView(View child, int index, ViewGroup.LayoutParams params) {
         super.addView(child, index, params);
-        updateWidth();
+        updateLayoutParams();
         updateBubbleAccessibilityStates();
         updateContentDescription();
     }
@@ -887,7 +887,7 @@
             mSelectedBubbleView = null;
             mBubbleBarBackground.showArrow(false);
         }
-        updateWidth();
+        updateLayoutParams();
         updateBubbleAccessibilityStates();
         updateContentDescription();
         mDismissedByDragBubbleView = null;
@@ -937,12 +937,6 @@
         }
     }
 
-    private void updateWidth() {
-        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
-        setLayoutParams(lp);
-    }
-
     private void updateLayoutParams() {
         LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
         lp.height = (int) getBubbleBarExpandedHeight();
@@ -1309,7 +1303,10 @@
         return totalIconSize + totalSpace + horizontalPadding;
     }
 
-    private float collapsedWidth() {
+    /**
+     * Get width of the bubble bar if it is collapsed
+     */
+    float collapsedWidth() {
         final int bubbleChildCount = getBubbleChildCount();
         final float horizontalPadding = 2 * mBubbleBarPadding;
         // If there are more than 2 bubbles, the first 2 should be visible when collapsed,
@@ -1479,8 +1476,9 @@
         pw.println("BubbleBarView state:");
         pw.println("  visibility: " + getVisibility());
         pw.println("  alpha: " + getAlpha());
-        pw.println("  translation Y: " + getTranslationY());
-        pw.println("  bubbles in bar (childCount = " + getChildCount() + ")");
+        pw.println("  translationY: " + getTranslationY());
+        pw.println("  childCount: " + getChildCount());
+        pw.println("  hasOverflow:  " + hasOverflow());
         for (BubbleView bubbleView: getBubbles()) {
             BubbleBarItem bubble = bubbleView.getBubble();
             String key = bubble == null ? "null" : bubble.getKey();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index cd0bca6..d9e3406 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -43,7 +43,7 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -80,12 +80,15 @@
 
     // These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
     private final MultiValueAlpha mBubbleBarAlpha;
-    private final AnimatedFloat mBubbleBarScale = new AnimatedFloat(this::updateScale);
+    private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
+    private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
     private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
             this::updateTranslationY);
 
     // Modified when swipe up is happening on the bubble bar or task bar.
     private float mBubbleBarSwipeUpTranslationY;
+    // Modified when bubble bar is springing back into the stash handle.
+    private float mBubbleBarStashTranslationY;
 
     // Whether the bar is hidden for a sysui state.
     private boolean mHiddenForSysui;
@@ -119,12 +122,13 @@
         mBubbleDragController = bubbleControllers.bubbleDragController;
         mTaskbarStashController = controllers.taskbarStashController;
         mTaskbarInsetsController = controllers.taskbarInsetsController;
-        mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
+        mBubbleBarViewAnimator = new BubbleBarViewAnimator(
+                mBarView, mBubbleStashController, mBubbleBarController::showExpandedView);
         mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
         onBubbleBarConfigurationChanged(/* animate= */ false);
         mActivity.addOnDeviceProfileChangeListener(
                 dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
-        mBubbleBarScale.updateValue(1f);
+        mBubbleBarScaleY.updateValue(1f);
         mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
         mBubbleBarClickListener = v -> expandBubbleBar();
         mBubbleDragController.setupBubbleBarView(mBarView);
@@ -254,19 +258,48 @@
         return mBubbleBarAlpha;
     }
 
-    public AnimatedFloat getBubbleBarScale() {
-        return mBubbleBarScale;
+    public AnimatedFloat getBubbleBarScaleX() {
+        return mBubbleBarScaleX;
+    }
+
+    public AnimatedFloat getBubbleBarScaleY() {
+        return mBubbleBarScaleY;
     }
 
     public AnimatedFloat getBubbleBarTranslationY() {
         return mBubbleBarTranslationY;
     }
 
+    public float getBubbleBarCollapsedWidth() {
+        return mBarView.collapsedWidth();
+    }
+
     public float getBubbleBarCollapsedHeight() {
         return mBarView.getBubbleBarCollapsedHeight();
     }
 
     /**
+     * @see BubbleBarView#getRelativePivotX()
+     */
+    public float getBubbleBarRelativePivotX() {
+        return mBarView.getRelativePivotX();
+    }
+
+    /**
+     * @see BubbleBarView#getRelativePivotY()
+     */
+    public float getBubbleBarRelativePivotY() {
+        return mBarView.getRelativePivotY();
+    }
+
+    /**
+     * @see BubbleBarView#setRelativePivot(float, float)
+     */
+    public void setBubbleBarRelativePivot(float x, float y) {
+        mBarView.setRelativePivot(x, y);
+    }
+
+    /**
      * Whether the bubble bar is visible or not.
      */
     public boolean isBubbleBarVisible() {
@@ -286,6 +319,14 @@
     }
 
     /**
+     * @return {@code true} if bubble bar is on the left edge of the screen, {@code false} if on
+     * the right
+     */
+    public boolean isBubbleBarOnLeft() {
+        return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl());
+    }
+
+    /**
      * Update bar {@link BubbleBarLocation}
      */
     public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
@@ -308,6 +349,15 @@
         return mBarView.getBubbleBarBounds();
     }
 
+    /** Checks that bubble bar is visible and that the motion event is within bounds. */
+    public boolean isEventOverBubbleBar(MotionEvent event) {
+        if (!isBubbleBarVisible()) return false;
+        final Rect bounds = getBubbleBarBounds();
+        final int bubbleBarTopOnScreen = mBarView.getRestingTopPositionOnScreen();
+        final float x = event.getX();
+        return event.getRawY() >= bubbleBarTopOnScreen && x >= bounds.left && x <= bounds.right;
+    }
+
     /** Whether a new bubble is animating. */
     public boolean isAnimatingNewBubble() {
         return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.isAnimating();
@@ -464,17 +514,24 @@
         updateTranslationY();
     }
 
-    private void updateTranslationY() {
-        mBarView.setTranslationY(mBubbleBarTranslationY.value
-                + mBubbleBarSwipeUpTranslationY);
+    /**
+     * Sets the translation of the bubble bar during the stash animation.
+     */
+    public void setTranslationYForStash(float transY) {
+        mBubbleBarStashTranslationY = transY;
+        updateTranslationY();
     }
 
-    /**
-     * Applies scale properties for the entire bubble bar.
-     */
-    private void updateScale() {
-        float scale = mBubbleBarScale.value;
+    private void updateTranslationY() {
+        mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
+                + mBubbleBarStashTranslationY);
+    }
+
+    private void updateScaleX(float scale) {
         mBarView.setScaleX(scale);
+    }
+
+    private void updateScaleY(float scale) {
         mBarView.setScaleY(scale);
     }
 
@@ -783,6 +840,7 @@
         pw.println("  mShouldShowEducation: " + mShouldShowEducation);
         pw.println("  mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
         pw.println("  mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
+        pw.println("  mOverflowAdded: " + mOverflowAdded);
         if (mBarView != null) {
             mBarView.dump(pw);
         } else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
index 8e9a2f6..12b1487 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -51,7 +51,7 @@
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.BubbleIconFactory;
 import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
 
 /**
  * Loads the necessary info to populate / present a bubble (name, icon, shortcut).
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index f554fcd..a459dd9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -29,7 +29,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarDragLayer;
-import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DismissView;
 import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
 
 /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
index 6c3f0d8..a8002a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
@@ -18,7 +18,7 @@
 package com.android.launcher3.taskbar.bubbles
 
 import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.DismissView
+import com.android.wm.shell.shared.bubbles.DismissView
 
 /**
  * Dismiss view is shared from WMShell. It requires setup with local resources.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 87f466f..adaba7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -29,8 +29,8 @@
 import androidx.dynamicanimation.animation.FloatPropertyCompat;
 
 import com.android.launcher3.R;
-import com.android.wm.shell.common.bubbles.DismissCircleView;
-import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DismissCircleView;
+import com.android.wm.shell.shared.bubbles.DismissView;
 import com.android.wm.shell.shared.animation.PhysicsAnimator;
 
 /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 656a266..42bd197 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -27,8 +27,8 @@
 import androidx.dynamicanimation.animation.FloatPropertyCompat;
 
 import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController.LocationChangeListener;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 
 /**
  * Controls bubble bar drag interactions.
@@ -77,6 +77,8 @@
     private BubbleBarPinController mBubbleBarPinController;
     private BubblePinController mBubblePinController;
 
+    private boolean mIsDragging;
+
     public BubbleDragController(TaskbarActivityContext activity) {
         mActivity = activity;
     }
@@ -240,6 +242,16 @@
         });
     }
 
+    /** Whether there is an item being dragged or not. */
+    public boolean isDragging() {
+        return mIsDragging;
+    }
+
+    /** Sets whether something is being dragged or not. */
+    public void setIsDragging(boolean isDragging) {
+        mIsDragging = isDragging;
+    }
+
     /**
      * Bubble touch listener for handling a single bubble view or bubble bar view while dragging.
      * The dragging starts after "shorter" long click (the long click duration might change):
@@ -436,6 +448,7 @@
 
         private void startDragging(@NonNull View view) {
             onDragStart();
+            BubbleDragController.this.setIsDragging(true);
             mActivity.setTaskbarWindowFullscreen(true);
             mAnimator = new BubbleDragAnimator(view);
             mAnimator.animateFocused();
@@ -452,6 +465,7 @@
         }
 
         private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
+            BubbleDragController.this.setIsDragging(false);
             Runnable onComplete = () -> {
                 mActivity.setTaskbarWindowFullscreen(false);
                 cleanUp(view);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
index 1341b53..af1666f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -28,8 +28,8 @@
 import androidx.core.view.updateLayoutParams
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BaseBubblePinController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
 
 /** Controller to manage pinning bubble bar to left or right when dragging starts from a bubble */
 class BubblePinController(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 8158fe7..fdd385a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -21,6 +21,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -28,6 +29,7 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
@@ -37,9 +39,9 @@
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
 import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
 
 /**
  * Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -49,23 +51,29 @@
     private final TaskbarActivityContext mActivity;
     private final StashedHandleView mStashedHandleView;
     private final MultiValueAlpha mStashedHandleAlpha;
+    private float mTranslationForSwipeY;
+    private float mTranslationForStashY;
 
     // Initialized in init.
     private BubbleBarViewController mBarViewController;
     private BubbleStashController mBubbleStashController;
     private RegionSamplingHelper mRegionSamplingHelper;
-    private int mBarSize;
-    private int mStashedTaskbarHeight;
+    // Height of the area for the stash handle. Handle will be drawn in the center of this.
+    // This is also the area where touch is handled on the handle.
+    private int mStashedBubbleBarHeight;
     private int mStashedHandleWidth;
     private int mStashedHandleHeight;
 
-    // The bounds we want to clip to in the settled state when showing the stashed handle.
+    // The bounds of the stashed handle in settled state.
     private final Rect mStashedHandleBounds = new Rect();
+    private float mStashedHandleRadius;
 
     // When the reveal animation is cancelled, we can assume it's about to create a new animation,
     // which should start off at the same point the cancelled one left off.
     private float mStartProgressForNextRevealAnim;
-    private boolean mWasLastRevealAnimReversed;
+    // Use a nullable boolean to handle initial case where the last animation direction is not known
+    @Nullable
+    private Boolean mWasLastRevealAnimReversed = null;
 
     // XXX: if there are more of these maybe do state flags instead
     private boolean mHiddenForSysui;
@@ -77,6 +85,7 @@
         mActivity = activity;
         mStashedHandleView = stashedHandleView;
         mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
+        mStashedHandleAlpha.setUpdateVisibility(true);
     }
 
     /** Initialize controller. */
@@ -84,26 +93,31 @@
         mBarViewController = bubbleControllers.bubbleBarViewController;
         mBubbleStashController = bubbleControllers.bubbleStashController;
 
+        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         Resources resources = mActivity.getResources();
         mStashedHandleHeight = resources.getDimensionPixelSize(
                 R.dimen.bubblebar_stashed_handle_height);
         mStashedHandleWidth = resources.getDimensionPixelSize(
                 R.dimen.bubblebar_stashed_handle_width);
-        mBarSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
 
-        final int bottomMargin = resources.getDimensionPixelSize(
-                R.dimen.transient_taskbar_bottom_margin);
-        mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
+        int barSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
+        // Use the max translation for bubble bar whether it is on the home screen or in app.
+        // Use values directly from device profile to avoid referencing other bubble controllers
+        // during init flow.
+        int maxTy = Math.max(deviceProfile.hotseatBarBottomSpacePx,
+                deviceProfile.taskbarBottomMargin);
+        // Adjust handle view size to accommodate the handle morphing into the bubble bar
+        mStashedHandleView.getLayoutParams().height = barSize + maxTy;
 
         mStashedHandleAlpha.get(0).setValue(0);
 
-        mStashedTaskbarHeight = resources.getDimensionPixelSize(
+        mStashedBubbleBarHeight = resources.getDimensionPixelSize(
                 R.dimen.bubblebar_stashed_size);
         mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
             @Override
             public void getOutline(View view, Outline outline) {
-                float stashedHandleRadius = view.getHeight() / 2f;
-                outline.setRoundRect(mStashedHandleBounds, stashedHandleRadius);
+                mStashedHandleRadius = view.getHeight() / 2f;
+                outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
             }
         });
 
@@ -132,28 +146,25 @@
     private void updateBounds(BubbleBarLocation bubbleBarLocation) {
         // As more bubbles get added, the icon bounds become larger. To ensure a consistent
         // handle bar position, we pin it to the edge of the screen.
-        final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
+        final int stashedCenterY = mStashedHandleView.getHeight() - mStashedBubbleBarHeight / 2;
+        final int stashedCenterX;
         if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
             final int left = mBarViewController.getHorizontalMargin();
-            mStashedHandleBounds.set(
-                    left,
-                    stashedCenterY - mStashedHandleHeight / 2,
-                    left + mStashedHandleWidth,
-                    stashedCenterY + mStashedHandleHeight / 2);
-            mStashedHandleView.setPivotX(0);
+            stashedCenterX = left + mStashedHandleWidth / 2;
         } else {
             final int right =
-                    mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
-            mStashedHandleBounds.set(
-                    right - mStashedHandleWidth,
-                    stashedCenterY - mStashedHandleHeight / 2,
-                    right,
-                    stashedCenterY + mStashedHandleHeight / 2);
-            mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
+                    mStashedHandleView.getRight() - mBarViewController.getHorizontalMargin();
+            stashedCenterX = right - mStashedHandleWidth / 2;
         }
-
+        mStashedHandleBounds.set(
+                stashedCenterX - mStashedHandleWidth / 2,
+                stashedCenterY - mStashedHandleHeight / 2,
+                stashedCenterX + mStashedHandleWidth / 2,
+                stashedCenterY + mStashedHandleHeight / 2
+        );
         mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
-        mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
+        mStashedHandleView.setPivotX(stashedCenterX);
+        mStashedHandleView.setPivotY(stashedCenterY);
     }
 
     public void onDestroy() {
@@ -162,6 +173,13 @@
     }
 
     /**
+     * Returns the width of the stashed handle.
+     */
+    public int getStashedWidth() {
+        return mStashedHandleWidth;
+    }
+
+    /**
      * Returns the height of the stashed handle.
      */
     public int getStashedHeight() {
@@ -169,13 +187,6 @@
     }
 
     /**
-     * Returns the height when the bubble bar is unstashed (so the height of the bubble bar).
-     */
-    public int getUnstashedHeight() {
-        return mBarSize;
-    }
-
-    /**
      * Called when system ui state changes. Bubbles don't show when the device is locked.
      */
     public void setHiddenForSysui(boolean hidden) {
@@ -242,7 +253,20 @@
      * Sets the translation of the stashed handle during the swipe up gesture.
      */
     public void setTranslationYForSwipe(float transY) {
-        mStashedHandleView.setTranslationY(transY);
+        mTranslationForSwipeY = transY;
+        updateTranslationY();
+    }
+
+    /**
+     * Sets the translation of the stashed handle during the spring on stash animation.
+     */
+    public void setTranslationYForStash(float transY) {
+        mTranslationForStashY = transY;
+        updateTranslationY();
+    }
+
+    private void updateTranslationY() {
+        mStashedHandleView.setTranslationY(mTranslationForSwipeY + mTranslationForStashY);
     }
 
     /** Returns the translation of the stashed handle. */
@@ -263,18 +287,17 @@
      * the size of where the bubble bar icons will be.
      */
     public Animator createRevealAnimToIsStashed(boolean isStashed) {
-        Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+        Rect bubbleBarBounds = getLocalBubbleBarBounds();
 
-        // Account for the full visual height of the bubble bar
-        int heightDiff = (mBarSize - bubbleBarBounds.height()) / 2;
-        bubbleBarBounds.top -= heightDiff;
-        bubbleBarBounds.bottom += heightDiff;
-        float stashedHandleRadius = mStashedHandleView.getHeight() / 2f;
+        float bubbleBarRadius = bubbleBarBounds.height() / 2f;
         final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
-                stashedHandleRadius, stashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
+                bubbleBarRadius, mStashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
 
         boolean isReversed = !isStashed;
-        boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+        // We are only changing direction when mWasLastRevealAnimReversed is set at least once
+        boolean changingDirection =
+                mWasLastRevealAnimReversed != null && mWasLastRevealAnimReversed != isReversed;
+
         mWasLastRevealAnimReversed = isReversed;
         if (changingDirection) {
             mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
@@ -291,6 +314,21 @@
         return revealAnim;
     }
 
+    /**
+     * Get bounds for the bubble bar in the space of the handle view
+     */
+    private Rect getLocalBubbleBarBounds() {
+        // Position the bubble bar bounds to the space of handle view
+        Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+        // Start by moving bubble bar bounds to the bottom of handle view
+        int height = bubbleBarBounds.height();
+        bubbleBarBounds.bottom = mStashedHandleView.getHeight();
+        bubbleBarBounds.top = bubbleBarBounds.bottom - height;
+        // Then apply translation that is applied to the bubble bar
+        bubbleBarBounds.offset(0, (int) mBubbleStashController.getBubbleBarTranslationY());
+        return bubbleBarBounds;
+    }
+
     /** Checks that the stash handle is visible and that the motion event is within bounds. */
     public boolean isEventOverHandle(MotionEvent ev) {
         if (mStashedHandleView.getVisibility() != VISIBLE) {
@@ -298,15 +336,11 @@
         }
 
         // the bounds of the handle only include the visible part, so we check that the Y coordinate
-        // is anywhere within the stashed taskbar height.
-        int top = mActivity.getDeviceProfile().heightPx - mStashedTaskbarHeight;
-
-        return (int) ev.getRawY() >= top && containsX((int) ev.getRawX());
-    }
-
-    /** Checks if the given x coordinate is within the stashed handle bounds. */
-    public boolean containsX(int x) {
-        return x >= mStashedHandleBounds.left && x <= mStashedHandleBounds.right;
+        // is anywhere within the stashed height of bubble bar (same as taskbar stashed height).
+        final int top = mActivity.getDeviceProfile().heightPx - mStashedBubbleBarHeight;
+        final float x = ev.getRawX();
+        return ev.getRawY() >= top && x >= mStashedHandleBounds.left
+                && x <= mStashedHandleBounds.right;
     }
 
     /** Set a bubble bar location */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index eb3b24b..591a9da 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -34,9 +34,9 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.icons.DotRenderer;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
 import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
 
 // TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
 
@@ -237,7 +237,11 @@
         mBubble = bubble;
         mIcon = bubble.getIcon();
         updateBubbleIcon();
-        mAppIcon.setImageBitmap(bubble.getBadge());
+        if (bubble.getInfo().showAppBadge()) {
+            mAppIcon.setImageBitmap(bubble.getBadge());
+        } else {
+            mAppIcon.setVisibility(GONE);
+        }
         mDotColor = bubble.getDotColor();
         mDotRenderer = new DotRenderer(mBubbleSize, bubble.getDotPath(), DEFAULT_PATH_SIZE);
         String contentDesc = bubble.getInfo().getTitle();
@@ -302,8 +306,10 @@
     }
 
     void setBadgeScale(float fraction) {
-        mAppIcon.setScaleX(fraction);
-        mAppIcon.setScaleY(fraction);
+        if (mAppIcon.getVisibility() == VISIBLE) {
+            mAppIcon.setScaleX(fraction);
+            mAppIcon.setScaleY(fraction);
+        }
     }
 
     boolean hasUnseenContent() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 2ed88d8..99c50f2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -36,6 +36,7 @@
 constructor(
     private val bubbleBarView: BubbleBarView,
     private val bubbleStashController: BubbleStashController,
+    private val onExpanded: Runnable,
     private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
 ) {
 
@@ -406,7 +407,7 @@
         springBackAnimation.spring(DynamicAnimation.TRANSLATION_Y, ty)
         springBackAnimation.addEndListener { _, _, _, _, _, _, _ ->
             if (animatingBubble?.expand == true) {
-                bubbleBarView.isExpanded = true
+                expandBubbleBar()
                 cancelHideAnimation()
             } else {
                 moveToState(AnimatingBubble.State.IN)
@@ -417,7 +418,7 @@
         ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
             .withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
             .withEndAction {
-                if (animatingBubble?.expand == true) bubbleBarView.isExpanded = true
+                if (animatingBubble?.expand == true) expandBubbleBar()
                 springBackAnimation.start()
             }
             .start()
@@ -451,7 +452,7 @@
         this.animatingBubble = animatingBubble.copy(expand = true)
         // if we're fully in and waiting to hide, cancel the hide animation and clean up
         if (animatingBubble.state == AnimatingBubble.State.IN) {
-            bubbleBarView.isExpanded = true
+            expandBubbleBar()
             cancelHideAnimation()
         }
     }
@@ -489,6 +490,11 @@
         this.animatingBubble = animatingBubble.copy(state = state)
     }
 
+    private fun expandBubbleBar() {
+        bubbleBarView.isExpanded = true
+        onExpanded.run()
+    }
+
     /**
      * Tracks the translation Y of the bubble bar during the animation. When the bubble bar expands
      * as part of the animation, the expansion should start after the bubble bar reaches the peak
@@ -510,7 +516,7 @@
             }
             val expand = animatingBubble?.expand ?: false
             if (reachedPeak && expand && !startedExpanding) {
-                bubbleBarView.isExpanded = true
+                expandBubbleBar()
                 startedExpanding = true
             }
             previousTy = ty
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 48eb7de..8d63217 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -23,8 +23,8 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
 import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
 import java.io.PrintWriter
 
 /** StashController that defines stashing behaviour for the taskbar modes. */
@@ -181,8 +181,5 @@
 
         /** How long to translate Y coordinate of the BubbleBar. */
         const val BAR_TRANSLATION_DURATION = 300L
-
-        /** The scale bubble bar animates to when being stashed. */
-        const val STASHED_BAR_SCALE = 0.5f
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 1b65019..eaf4bf9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -30,8 +30,8 @@
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
 import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
 import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
 
 class PersistentBubbleStashController(
     private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
@@ -116,7 +116,7 @@
         bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
         // bubble bar has only alpha property, getting it at index 0
         bubbleBarAlphaAnimator = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
-        bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScale
+        bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScaleY
     }
 
     private fun animateAfterUnlock() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 1a4b982..1157305 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -17,30 +17,36 @@
 package com.android.launcher3.taskbar.bubbles.stashing
 
 import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorSet
-import android.content.res.Resources
+import android.content.Context
 import android.view.MotionEvent
 import android.view.View
 import androidx.annotation.VisibleForTesting
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.app.animation.Interpolators.LINEAR
 import com.android.launcher3.R
 import com.android.launcher3.anim.AnimatedFloat
-import com.android.launcher3.taskbar.StashedHandleViewController
+import com.android.launcher3.anim.SpringAnimationBuilder
 import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
 import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
 import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import kotlin.math.max
 
 class TransientBubbleStashController(
     private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
-    resources: Resources
+    private val context: Context
 ) : BubbleStashController {
 
     private lateinit var bubbleBarViewController: BubbleBarViewController
@@ -50,14 +56,21 @@
     // stash view properties
     private var bubbleStashedHandleViewController: BubbleStashedHandleViewController? = null
     private var stashHandleViewAlpha: MultiPropertyFactory<View>.MultiProperty? = null
+    private var translationYDuringStash = AnimatedFloat { transY ->
+        bubbleStashedHandleViewController?.setTranslationYForStash(transY)
+        bubbleBarViewController.setTranslationYForStash(transY)
+    }
+    private val stashHandleStashVelocity =
+        context.resources.getDimension(R.dimen.bubblebar_stashed_handle_spring_velocity_dp_per_s)
     private var stashedHeight: Int = 0
 
     // bubble bar properties
     private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty
     private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
-    private lateinit var bubbleBarScale: AnimatedFloat
-    private val mHandleCenterFromScreenBottom =
-        resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
+    private lateinit var bubbleBarScaleX: AnimatedFloat
+    private lateinit var bubbleBarScaleY: AnimatedFloat
+    private val handleCenterFromScreenBottom =
+        context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
 
     private var animator: AnimatorSet? = null
 
@@ -136,12 +149,10 @@
         bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
         // bubble bar has only alpha property, getting it at index 0
         bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
-        bubbleBarScale = bubbleBarViewController.bubbleBarScale
+        bubbleBarScaleX = bubbleBarViewController.bubbleBarScaleX
+        bubbleBarScaleY = bubbleBarViewController.bubbleBarScaleY
         stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
-        stashHandleViewAlpha =
-            bubbleStashedHandleViewController
-                ?.stashedHandleAlpha
-                ?.get(StashedHandleViewController.ALPHA_INDEX_STASHED)
+        stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0)
     }
 
     private fun animateAfterUnlock() {
@@ -149,7 +160,8 @@
         if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
             isStashed = false
             animatorSet.playTogether(
-                bubbleBarScale.animateToValue(1f),
+                bubbleBarScaleX.animateToValue(1f),
+                bubbleBarScaleY.animateToValue(1f),
                 bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
                 bubbleBarAlpha.animateToValue(1f)
             )
@@ -169,7 +181,8 @@
         stashHandleViewAlpha?.value = 0f
         this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
         bubbleBarAlpha.setValue(1f)
-        bubbleBarScale.updateValue(1f)
+        bubbleBarScaleX.updateValue(1f)
+        bubbleBarScaleY.updateValue(1f)
         isStashed = false
         onIsStashedChanged()
     }
@@ -179,7 +192,8 @@
         stashHandleViewAlpha?.value = 1f
         this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
         bubbleBarAlpha.setValue(0f)
-        bubbleBarScale.updateValue(STASHED_BAR_SCALE)
+        bubbleBarScaleX.updateValue(getStashScaleX())
+        bubbleBarScaleY.updateValue(getStashScaleY())
         isStashed = true
         onIsStashedChanged()
     }
@@ -223,11 +237,11 @@
         // the difference between the centers of the handle and the bubble bar is the difference
         // between their distance from the bottom of the screen.
         val barCenter: Float = bubbleBarViewController.bubbleBarCollapsedHeight / 2f
-        return mHandleCenterFromScreenBottom - barCenter
+        return handleCenterFromScreenBottom - barCenter
     }
 
     override fun getStashedHandleTranslationForNewBubbleAnimation(): Float {
-        return -mHandleCenterFromScreenBottom
+        return -handleCenterFromScreenBottom
     }
 
     override fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>? {
@@ -245,7 +259,19 @@
     override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
 
     private fun getStashTranslation(): Float {
-        return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
+        return bubbleBarTranslationY / 2f
+    }
+
+    @VisibleForTesting
+    fun getStashScaleX(): Float {
+        val handleWidth = bubbleStashedHandleViewController?.stashedWidth ?: 0
+        return handleWidth / bubbleBarViewController.bubbleBarCollapsedWidth
+    }
+
+    @VisibleForTesting
+    fun getStashScaleY(): Float {
+        val handleHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
+        return handleHeight / bubbleBarViewController.bubbleBarCollapsedHeight
     }
 
     /**
@@ -258,61 +284,93 @@
     @Suppress("SameParameterValue")
     private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet {
         val animatorSet = AnimatorSet()
-        val fullLengthAnimatorSet = AnimatorSet()
-        // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
-        val firstHalfAnimatorSet = AnimatorSet()
-        val secondHalfAnimatorSet = AnimatorSet()
-        val firstHalfDurationScale: Float
-        val secondHalfDurationScale: Float
-        val stashHandleAlphaValue: Float
-        if (isStashed) {
-            firstHalfDurationScale = 0.75f
-            secondHalfDurationScale = 0.5f
-            stashHandleAlphaValue = 1f
-            fullLengthAnimatorSet.play(
-                bubbleBarTranslationYAnimator.animateToValue(getStashTranslation())
-            )
-            firstHalfAnimatorSet.playTogether(
-                bubbleBarAlpha.animateToValue(0f),
-                bubbleBarScale.animateToValue(STASHED_BAR_SCALE)
-            )
-        } else {
-            firstHalfDurationScale = 0.5f
-            secondHalfDurationScale = 0.75f
-            stashHandleAlphaValue = 0f
-            fullLengthAnimatorSet.playTogether(
-                bubbleBarScale.animateToValue(1f),
-                bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY)
-            )
-            secondHalfAnimatorSet.playTogether(bubbleBarAlpha.animateToValue(1f))
-        }
-        stashHandleViewAlpha?.let {
-            secondHalfAnimatorSet.playTogether(it.animateToValue(stashHandleAlphaValue))
-        }
-        bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.let {
-            fullLengthAnimatorSet.play(it)
-        }
-        fullLengthAnimatorSet.setDuration(duration)
-        firstHalfAnimatorSet.setDuration((duration * firstHalfDurationScale).toLong())
-        secondHalfAnimatorSet.setDuration((duration * secondHalfDurationScale).toLong())
-        secondHalfAnimatorSet.startDelay = (duration * (1 - secondHalfDurationScale)).toLong()
-        animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, secondHalfAnimatorSet)
-        animatorSet.addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationEnd(animation: Animator) {
-                    animator = null
-                    controllersAfterInitAction.runAfterInit {
-                        if (isStashed) {
-                            bubbleBarViewController.isExpanded = false
-                        }
-                        taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
-                    }
-                }
+
+        val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+        val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
+        animatorSet.play(
+            createStashAlphaAnimator(isStashed).apply {
+                this.duration = max(0L, alphaDuration - alphaDelay)
+                this.startDelay = alphaDelay
+                this.interpolator = LINEAR
             }
         )
+
+        animatorSet.play(
+            createSpringOnStashAnimator(isStashed).apply {
+                this.duration = duration
+                this.interpolator = LINEAR
+            }
+        )
+
+        animatorSet.play(
+            bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply {
+                this.duration = duration
+                this.interpolator = EMPHASIZED
+            }
+        )
+
+        val pivotX = if (bubbleBarViewController.isBubbleBarOnLeft) 0f else 1f
+        animatorSet.play(
+            createScaleAnimator(isStashed).apply {
+                this.duration = duration
+                this.interpolator = EMPHASIZED
+                this.setBubbleBarPivotDuringAnim(pivotX, 1f)
+            }
+        )
+
+        val translationYTarget = if (isStashed) getStashTranslation() else bubbleBarTranslationY
+        animatorSet.play(
+            bubbleBarTranslationYAnimator.animateToValue(translationYTarget).apply {
+                this.duration = duration
+                this.interpolator = EMPHASIZED
+            }
+        )
+
+        animatorSet.doOnEnd {
+            animator = null
+            controllersAfterInitAction.runAfterInit {
+                if (isStashed) {
+                    bubbleBarViewController.isExpanded = false
+                }
+                taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+            }
+        }
         return animatorSet
     }
 
+    private fun createStashAlphaAnimator(isStashed: Boolean): AnimatorSet {
+        val stashHandleAlphaTarget = if (isStashed) 1f else 0f
+        val barAlphaTarget = if (isStashed) 0f else 1f
+        return AnimatorSet().apply {
+            play(bubbleBarAlpha.animateToValue(barAlphaTarget))
+            play(stashHandleViewAlpha?.animateToValue(stashHandleAlphaTarget))
+        }
+    }
+
+    private fun createSpringOnStashAnimator(isStashed: Boolean): Animator {
+        if (!isStashed) {
+            // Animate the stash translation back to 0
+            return translationYDuringStash.animateToValue(0f)
+        }
+        // Apply a spring to the handle
+        return SpringAnimationBuilder(context)
+            .setStartValue(translationYDuringStash.value)
+            .setEndValue(0f)
+            .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+            .setStiffness(SpringForce.STIFFNESS_LOW)
+            .setStartVelocity(stashHandleStashVelocity)
+            .build(translationYDuringStash, AnimatedFloat.VALUE)
+    }
+
+    private fun createScaleAnimator(isStashed: Boolean): AnimatorSet {
+        val scaleXTarget = if (isStashed) getStashScaleX() else 1f
+        val scaleYTarget = if (isStashed) getStashScaleY() else 1f
+        return AnimatorSet().apply {
+            play(bubbleBarScaleX.animateToValue(scaleXTarget))
+            play(bubbleBarScaleY.animateToValue(scaleYTarget))
+        }
+    }
+
     private fun onIsStashedChanged() {
         controllersAfterInitAction.runAfterInit {
             taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -363,13 +421,23 @@
     }
 
     private fun Animator.updateTouchRegionOnAnimationEnd(): Animator {
-        this.addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationEnd(animation: Animator) {
-                    onIsStashedChanged()
-                }
+        doOnEnd { onIsStashedChanged() }
+        return this
+    }
+
+    private fun Animator.setBubbleBarPivotDuringAnim(pivotX: Float, pivotY: Float): Animator {
+        var initialPivotX = Float.NaN
+        var initialPivotY = Float.NaN
+        doOnStart {
+            initialPivotX = bubbleBarViewController.bubbleBarRelativePivotX
+            initialPivotY = bubbleBarViewController.bubbleBarRelativePivotY
+            bubbleBarViewController.setBubbleBarRelativePivot(pivotX, pivotY)
+        }
+        doOnEnd {
+            if (!initialPivotX.isNaN() && !initialPivotY.isNaN()) {
+                bubbleBarViewController.setBubbleBarRelativePivot(initialPivotX, initialPivotY)
             }
-        )
+        }
         return this
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 7d2d36d..726800c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -18,18 +18,27 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
 import android.util.AttributeSet
 import android.view.LayoutInflater
-import android.widget.LinearLayout
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewConfiguration
 import androidx.annotation.DimenRes
 import androidx.annotation.DrawableRes
 import androidx.core.view.setPadding
 import com.android.launcher3.R
 import com.android.launcher3.Utilities.dpToPx
-import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR
+import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
 import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarViewCallbacks
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
+import com.android.quickstep.DeviceConfigWrapper
+import com.android.quickstep.util.AssistStateManager
 
 /** Taskbar all apps button container for customizable taskbar. */
 class TaskbarAllAppsButtonContainer
@@ -38,19 +47,21 @@
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
-) : LinearLayout(context, attrs), TaskbarContainer {
+) : IconButtonView(context, attrs), TaskbarContainer {
 
-    private val allAppsButton: IconButtonView =
-        LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, this, false)
-            as IconButtonView
     private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+    private var allAppsTouchTriggered = false
+    private var allAppsTouchRunnable: Runnable? = null
+    private var allAppsButtonTouchDelayMs: Long = ViewConfiguration.getLongPressTimeout().toLong()
+    private lateinit var taskbarViewCallbacks: TaskbarViewCallbacks
 
     override val spaceNeeded: Int
         get() {
-            return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+            return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
         }
 
     init {
+        LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, null, false)
         setUpIcon()
     }
 
@@ -58,24 +69,39 @@
     private fun setUpIcon() {
         val drawable =
             resources.getDrawable(
-                getAllAppsButton(activityContext.taskbarFeatureEvaluator!!.isTransient)
+                getAllAppsButton(activityContext.taskbarFeatureEvaluator.isTransient)
             )
-        val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+        backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
+        setIconDrawable(drawable)
+        setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+        setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
+    }
 
-        allAppsButton.setIconDrawable(drawable)
-        allAppsButton.setPadding(padding)
-        allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
-
-        // TODO(b/356465292) : add click listeners in future cl
-        addView(allAppsButton)
+    @SuppressLint("ClickableViewAccessibility")
+    fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+        taskbarViewCallbacks = callbacks
+        setOnClickListener(this::onAllAppsButtonClick)
+        setOnLongClickListener(this::onAllAppsButtonLongClick)
+        setOnTouchListener(this::onAllAppsButtonTouch)
+        isHapticFeedbackEnabled = taskbarViewCallbacks.isAllAppsButtonHapticFeedbackEnabled()
+        allAppsTouchRunnable = Runnable {
+            taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+            allAppsTouchTriggered = true
+        }
+        val assistStateManager = AssistStateManager.INSTANCE[mContext]
+        if (
+            DeviceConfigWrapper.get().customLpaaThresholds &&
+                assistStateManager.lpnhDurationMillis.isPresent
+        ) {
+            allAppsButtonTouchDelayMs = assistStateManager.lpnhDurationMillis.get()
+        }
     }
 
     @DrawableRes
     private fun getAllAppsButton(isTransientTaskbar: Boolean): Int {
         val shouldSelectTransientIcon =
-            isTransientTaskbar ||
-                (FeatureFlags.enableTaskbarPinning() && !activityContext.isThreeButtonNav)
-        return if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+            isTransientTaskbar || (enableTaskbarPinning() && !activityContext.isThreeButtonNav)
+        return if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
             if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button
             else R.drawable.ic_taskbar_all_apps_search_button
         } else {
@@ -88,10 +114,43 @@
     fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int {
         return if (isTransientTaskbar) {
             R.dimen.transient_taskbar_all_apps_button_translation_x_offset
-        } else if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+        } else if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
             R.dimen.taskbar_all_apps_search_button_translation_x_offset
         } else {
             R.dimen.taskbar_all_apps_button_translation_x_offset
         }
     }
+
+    private fun onAllAppsButtonTouch(view: View, ev: MotionEvent): Boolean {
+        when (ev.action) {
+            MotionEvent.ACTION_DOWN -> {
+                allAppsTouchTriggered = false
+                MAIN_EXECUTOR.handler.postDelayed(allAppsTouchRunnable!!, allAppsButtonTouchDelayMs)
+            }
+            MotionEvent.ACTION_UP,
+            MotionEvent.ACTION_CANCEL -> cancelAllAppsButtonTouch()
+        }
+        return false
+    }
+
+    private fun cancelAllAppsButtonTouch() {
+        MAIN_EXECUTOR.handler.removeCallbacks(allAppsTouchRunnable!!)
+        // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
+        // the next frame, so we need to post twice and delay the reset.
+        this.post { this.post { allAppsTouchTriggered = false } }
+    }
+
+    private fun onAllAppsButtonClick(view: View) {
+        if (!allAppsTouchTriggered) {
+            taskbarViewCallbacks.triggerAllAppsButtonClick(view)
+        }
+    }
+
+    // Handle long click from Switch Access and Voice Access
+    private fun onAllAppsButtonLongClick(view: View): Boolean {
+        if (!MAIN_EXECUTOR.handler.hasCallbacks(allAppsTouchRunnable!!) && !allAppsTouchTriggered) {
+            taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+        }
+        return true
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index 26e71f7..1fb835a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -18,13 +18,15 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
 import android.util.AttributeSet
 import android.view.LayoutInflater
-import android.widget.LinearLayout
 import androidx.core.view.setPadding
 import com.android.launcher3.R
 import com.android.launcher3.Utilities.dpToPx
 import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarViewCallbacks
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
 
@@ -35,31 +37,30 @@
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
-) : LinearLayout(context, attrs), TaskbarContainer {
-
-    private val taskbarDivider: IconButtonView =
-        LayoutInflater.from(context).inflate(R.layout.taskbar_divider, this, false)
-            as IconButtonView
+) : IconButtonView(context, attrs), TaskbarContainer {
     private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
 
     override val spaceNeeded: Int
         get() {
-            return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+            return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
         }
 
     init {
+        LayoutInflater.from(context).inflate(R.layout.taskbar_divider, null, false)
         setUpIcon()
     }
 
     @SuppressLint("UseCompatLoadingForDrawables")
     fun setUpIcon() {
+        backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
         val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
-        val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+        setIconDrawable(drawable)
+        setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+    }
 
-        taskbarDivider.setIconDrawable(drawable)
-        taskbarDivider.setPadding(padding)
-
-        // TODO(b/356465292):: add click listeners in future cl
-        addView(taskbarDivider)
+    @SuppressLint("ClickableViewAccessibility")
+    fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+        setOnLongClickListener(callbacks.taskbarDividerLongClickListener)
+        setOnTouchListener(callbacks.taskbarDividerRightClickListener)
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
index 887eb01..6be0828 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
@@ -19,10 +19,11 @@
 /** Taskbar Icon Specs */
 object TaskbarIconSpecs {
 
-    val iconSize40dp = TaskbarIconSize(40)
-    val iconSize44dp = TaskbarIconSize(44)
-    val iconSize48dp = TaskbarIconSize(48)
-    val iconSize52dp = TaskbarIconSize(52)
+    // Mapping of visual icon size to icon specs value http://b/235886078
+    val iconSize40dp = TaskbarIconSize(44)
+    val iconSize44dp = TaskbarIconSize(48)
+    val iconSize48dp = TaskbarIconSize(52)
+    val iconSize52dp = TaskbarIconSize(57)
 
     val transientTaskbarIconSizes = arrayOf(iconSize44dp, iconSize48dp, iconSize52dp)
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
index 761b47e..f37b2c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
@@ -25,14 +25,14 @@
     numRows: Int = taskbarActivityContext.deviceProfile.inv.numRows,
     numColumns: Int = taskbarActivityContext.deviceProfile.inv.numColumns,
 ) {
-    var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numRows, numColumns)
+    var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numColumns, numRows)
 
     // TODO(b/341146605) : initialize it to taskbar container in later cl.
     private var taskbarContainer: List<TaskbarContainer> = emptyList()
 
     val taskbarIconPadding: Int =
-        if (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size > taskbarIconSize.size) {
-            (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size - taskbarIconSize.size) / 2
+        if (TaskbarIconSpecs.iconSize52dp.size > taskbarIconSize.size) {
+            (TaskbarIconSpecs.iconSize52dp.size - taskbarIconSize.size) / 2
         } else {
             0
         }
@@ -44,10 +44,10 @@
             TaskbarIconSpecs.defaultPersistentIconMargin
         }
 
-    fun getIconSizeByGrid(row: Int, column: Int): TaskbarIconSize {
+    fun getIconSizeByGrid(columns: Int, rows: Int): TaskbarIconSize {
         return if (taskbarFeatureEvaluator.isTransient) {
             TaskbarIconSpecs.transientTaskbarIconSizeByGridSize.getOrDefault(
-                TransientTaskbarIconSizeKey(row, column, taskbarFeatureEvaluator.isLandscape),
+                TransientTaskbarIconSizeKey(columns, rows, taskbarFeatureEvaluator.isLandscape),
                 TaskbarIconSpecs.defaultTransientIconSize,
             )
         } else {
@@ -102,6 +102,6 @@
 
 data class TaskbarIconSize(val size: Int)
 
-data class TransientTaskbarIconSizeKey(val row: Int, val column: Int, val isLandscape: Boolean)
+data class TransientTaskbarIconSizeKey(val columns: Int, val rows: Int, val isLandscape: Boolean)
 
 data class TaskbarIconMarginSize(val size: Int)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 110ca16..4590efe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.Keyframe;
@@ -39,6 +40,7 @@
 import android.os.Process;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.Property;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 
@@ -71,12 +73,27 @@
  */
 public class PredictedAppIcon extends DoubleShadowBubbleTextView {
 
+    private static final float RING_SCALE_START_VALUE = 0.75f;
     private static final int RING_SHADOW_COLOR = 0x99000000;
     private static final float RING_EFFECT_RATIO = 0.095f;
 
     private static final long ICON_CHANGE_ANIM_DURATION = 360;
     private static final long ICON_CHANGE_ANIM_STAGGER = 50;
 
+    private static final Property<PredictedAppIcon, Float> RING_SCALE_PROPERTY =
+            new Property<>(Float.TYPE, "ringScale") {
+                @Override
+                public Float get(PredictedAppIcon icon) {
+                    return icon.mRingScale;
+                }
+
+                @Override
+                public void set(PredictedAppIcon icon, Float value) {
+                    icon.mRingScale = value;
+                    icon.invalidate();
+                }
+            };
+
     boolean mIsDrawingDot = false;
     private final DeviceProfile mDeviceProfile;
     private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -96,6 +113,11 @@
     private Animator mSlotMachineAnim;
     private float mSlotMachineIconTranslationY;
 
+    // Used to animate the "ring" around predicted icons
+    private float mRingScale = 1f;
+    private boolean mForceHideRing = false;
+    private Animator mRingScaleAnim;
+
     private static final FloatProperty<PredictedAppIcon> SLOT_MACHINE_TRANSLATION_Y =
             new FloatProperty<PredictedAppIcon>("slotMachineTranslationY") {
         @Override
@@ -356,17 +378,52 @@
         }
     }
 
+    @Override
+    public void setForceHideRing(boolean forceHideRing) {
+        if (mForceHideRing == forceHideRing) {
+            return;
+        }
+        mForceHideRing = forceHideRing;
+
+        if (forceHideRing) {
+            invalidate();
+        } else {
+            animateRingScale(RING_SCALE_START_VALUE, 1);
+        }
+    }
+
+    private void cancelRingScaleAnim() {
+        if (mRingScaleAnim != null) {
+            mRingScaleAnim.cancel();
+        }
+    }
+
+    private void animateRingScale(float... ringScale) {
+        cancelRingScaleAnim();
+        mRingScaleAnim = ObjectAnimator.ofFloat(this, RING_SCALE_PROPERTY, ringScale);
+        mRingScaleAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mRingScaleAnim = null;
+            }
+        });
+        mRingScaleAnim.start();
+    }
+
     private void drawEffect(Canvas canvas) {
-        // Don't draw ring effect if item is about to be dragged.
-        if (mDrawForDrag) {
+        // Don't draw ring effect if item is about to be dragged or if the icon is not visible.
+        if (mDrawForDrag || !mIsIconVisible || mForceHideRing) {
             return;
         }
         mIconRingPaint.setColor(RING_SHADOW_COLOR);
         mIconRingPaint.setMaskFilter(mShadowFilter);
+        int count = canvas.save();
+        canvas.scale(mRingScale, mRingScale, canvas.getWidth() / 2f, canvas.getHeight() / 2f);
         canvas.drawPath(mRingPath, mIconRingPaint);
         mIconRingPaint.setColor(mPlateColor);
         mIconRingPaint.setMaskFilter(null);
         canvas.drawPath(mRingPath, mIconRingPaint);
+        canvas.restoreToCount(count);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 17735e1..0b385d9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -22,7 +22,6 @@
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
 import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -499,10 +498,8 @@
         boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
         if (started) {
             DeviceProfile profile = getDeviceProfile();
-            boolean willUserBeActive =
-                    (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
             boolean visible = (state == NORMAL || state == OVERVIEW)
-                    && (willUserBeActive || isUserActive())
+                    && isUserActive()
                     && !profile.isVerticalBarLayout()
                     && !mIsOverlayVisible;
             SystemUiProxy.INSTANCE.get(this)
@@ -613,7 +610,7 @@
                                         .append(" is missing."),
                                 QUICK_SWITCH_FROM_HOME_FALLBACK);
                     }
-                    taskToLaunch.launchTask(success -> {
+                    taskToLaunch.launchWithoutAnimation(success -> {
                         if (!success) {
                             getStateManager().goToState(OVERVIEW);
                         } else {
@@ -696,9 +693,7 @@
         // Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
         // work, we must opt-in BEFORE registering back dispatcher. So we need to call
         // setEnableOnBackInvokedCallback() before super.onCreate()
-        if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
-            getApplicationInfo().setEnableOnBackInvokedCallback(true);
-        }
+        getApplicationInfo().setEnableOnBackInvokedCallback(true);
         super.onCreate(savedInstanceState);
         if (savedInstanceState != null) {
             mPendingSplitSelectInfo = ObjectWrapper.unwrap(
@@ -910,8 +905,7 @@
         // event won't go through ViewRootImpl#InputStage#onProcess.
         // So when receive back key, try to do the same check thing in
         // ViewRootImpl#NativePreImeInputStage#onProcess
-        if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
-                || event.getKeyCode() != KeyEvent.KEYCODE_BACK
+        if (event.getKeyCode() != KeyEvent.KEYCODE_BACK
                 || event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
             return false;
         }
@@ -922,10 +916,6 @@
 
     @Override
     protected void registerBackDispatcher() {
-        if (!enablePredictiveBackGesture()) {
-            super.registerBackDispatcher();
-            return;
-        }
         getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
                 OnBackInvokedDispatcher.PRIORITY_DEFAULT,
                 new OnBackAnimationCallback() {
@@ -1279,10 +1269,6 @@
         return ObjectWrapper.wrap(new Integer(info.id));
     }
 
-    public void setHintUserWillBeActive() {
-        addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
-    }
-
     @Override
     public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
         super.onDisplayInfoChanged(context, info, flags);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 2625646..1ba784b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,7 +17,6 @@
 
 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 
 import android.content.Context;
 import android.graphics.Color;
@@ -107,8 +106,7 @@
 
     @Override
     public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
-        if (ENABLE_SHELL_TRANSITIONS) return false;
-        return super.isTaskbarAlignedWithHotseat(launcher);
+        return false;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 6822f1b..b165cdd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -209,7 +209,7 @@
         TaskView taskView = recentsView.getRunningTaskView();
         if (taskView != null) {
             if (recentsView.isTaskViewFullyVisible(taskView)) {
-                taskView.launchTasks();
+                taskView.launchWithAnimation();
             } else {
                 recentsView.snapToPage(recentsView.indexOfChild(taskView));
             }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index d1aa472..ff726e6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -221,11 +220,6 @@
             mCancelSplitRunnable.accept(animatorSet, duration);
             animatorSet.start();
         }
-        if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() &&
-                ((mFromState == NORMAL && mToState == ALL_APPS)
-                        || (mFromState == ALL_APPS && mToState == NORMAL)) && isFling) {
-            mVibratorWrapper.vibrateForDragBump();
-        }
     }
 
     private void onMotionPauseDetected() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index eafc5b6..202276e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -181,7 +181,7 @@
                         // - The task is snapped
                         mAllowGoingDown = i == mRecentsView.getCurrentPage()
                                 && DisplayController.getNavigationMode(mContainer).hasGestures
-                                && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask())
+                                && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isLargeTile())
                                 && mRecentsView.isTaskInExpectedScrollPosition(i);
 
                         directionsToDetectScroll = mAllowGoingDown ? DIRECTION_BOTH : upDirection;
@@ -310,7 +310,7 @@
                 // Set mOverrideVelocity to control task dismiss velocity in onDragEnd
                 int velocityDimenId = R.dimen.default_task_dismiss_drag_velocity;
                 if (mRecentsView.showAsGrid()) {
-                    if (mTaskBeingDragged.isFocusedTask()) {
+                    if (mTaskBeingDragged.isLargeTile()) {
                         velocityDimenId =
                                 R.dimen.default_task_dismiss_drag_velocity_grid_focus_task;
                     } else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 5392b70..55489bb 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -97,6 +97,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.jank.Cuj;
 import com.android.internal.util.LatencyTracker;
@@ -170,10 +171,12 @@
 /**
  * Handles the navigation gestures when Launcher is the default home activity.
  */
-public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
-        Q extends RecentsView, S extends BaseState<S>>
-        extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
-        RecentsAnimationCallbacks.RecentsAnimationListener {
+public abstract class AbsSwipeUpHandler<
+        RECENTS_CONTAINER extends Context & RecentsViewContainer,
+        RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+        STATE extends BaseState<STATE>>
+        extends SwipeUpAnimationLogic
+        implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener {
     private static final String TAG = "AbsSwipeUpHandler";
 
     private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
@@ -181,7 +184,7 @@
     // Fraction of the scroll and transform animation in which the current task fades out
     private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f;
 
-    protected final BaseContainerInterface<S, T> mContainerInterface;
+    protected final BaseContainerInterface<STATE, RECENTS_CONTAINER> mContainerInterface;
     protected final InputConsumerProxy mInputConsumerProxy;
     protected final ActivityInitListener mActivityInitListener;
     // Callbacks to be made once the recents animation starts
@@ -192,8 +195,8 @@
     protected @Nullable RecentsAnimationController mRecentsAnimationController;
     protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController;
     protected RecentsAnimationTargets mRecentsAnimationTargets;
-    protected @Nullable T mContainer;
-    protected @Nullable Q mRecentsView;
+    protected @Nullable RECENTS_CONTAINER mContainer;
+    protected @Nullable RECENTS_VIEW mRecentsView;
     protected Runnable mGestureEndCallback;
     protected MultiStateCallback mStateCallback;
     protected boolean mCanceled;
@@ -486,11 +489,11 @@
             return false;
         }
 
-        T createdContainer = (T) mContainerInterface.getCreatedContainer();
+        RECENTS_CONTAINER createdContainer = mContainerInterface.getCreatedContainer();
         if (createdContainer != null) {
             initTransitionEndpoints(createdContainer.getDeviceProfile());
         }
-        final T container = (T) mContainerInterface.getCreatedContainer();
+        final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
         if (mContainer == container) {
             return true;
         }
@@ -564,7 +567,7 @@
     }
 
     private void onLauncherStart() {
-        final T container = (T) mContainerInterface.getCreatedContainer();
+        final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
         if (container == null || mContainer != container) {
             return;
         }
@@ -734,11 +737,18 @@
     }
 
     private void maybeUpdateRecentsAttachedState() {
-        maybeUpdateRecentsAttachedState(true /* animate */);
+        maybeUpdateRecentsAttachedState(/* animate= */ true);
     }
 
     protected void maybeUpdateRecentsAttachedState(boolean animate) {
-        maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
+        maybeUpdateRecentsAttachedState(animate, /* moveRunningTask= */ false);
+    }
+
+    protected void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+        maybeUpdateRecentsAttachedState(
+                animate,
+                moveRunningTask,
+                mRecentsView != null && mRecentsView.shouldUpdateRunningTaskAlpha());
     }
 
     /**
@@ -749,8 +759,10 @@
      * Note this method has no effect unless the navigation mode is NO_BUTTON.
      * @param animate whether to animate when attaching RecentsView
      * @param moveRunningTask whether to move running task to front when attaching
+     * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
      */
-    private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+    private void maybeUpdateRecentsAttachedState(
+            boolean animate, boolean moveRunningTask, boolean updateRunningTaskAlpha) {
         if ((!mDeviceState.isFullyGesturalNavMode() && !mGestureState.isTrackpadGesture())
                 || mRecentsView == null) {
             return;
@@ -781,7 +793,8 @@
             // TaskView jumping to new position as we move the tasks.
             mRecentsView.moveRunningTaskToFront();
         }
-        mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
+        mAnimationFactory.setRecentsAttachedToAppWindow(
+                recentsAttachedToAppWindow, animate, updateRunningTaskAlpha);
 
         // Reapply window transform throughout the attach animation, as the animation affects how
         // much the window is bound by overscroll (vs moving freely).
@@ -939,7 +952,6 @@
             // We will handle the sysui flags based on the centermost task view.
             mRecentsAnimationController.setUseLauncherSystemBarFlags(swipeUpThresholdPassed
                     ||  (quickswitchThresholdPassed && centermostTaskFlags != 0));
-            mRecentsAnimationController.setSplitScreenMinimized(mContext, swipeUpThresholdPassed);
             // Provide a hint to WM the direction that we will be settling in case the animation
             // needs to be canceled
             mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
@@ -1087,7 +1099,7 @@
      */
     @UiThread
     private void notifyGestureStarted() {
-        final T curActivity = mContainer;
+        final RECENTS_CONTAINER curActivity = mContainer;
         if (curActivity != null) {
             // Once the gesture starts, we can no longer transition home through the button, so
             // reset the force override of the activity visibility
@@ -1158,7 +1170,8 @@
     /**
      * Called if the end target has been set and the recents animation is started.
      */
-    private void onCalculateEndTarget() {
+    @VisibleForTesting
+    protected void onCalculateEndTarget() {
         final GestureEndTarget endTarget = mGestureState.getEndTarget();
 
         switch (endTarget) {
@@ -1171,7 +1184,8 @@
         }
     }
 
-    private void onSettledOnEndTarget() {
+    @VisibleForTesting
+    protected void onSettledOnEndTarget() {
         // Fast-finish the attaching animation if it's still running.
         maybeUpdateRecentsAttachedState(false);
         final GestureEndTarget endTarget = mGestureState.getEndTarget();
@@ -1407,7 +1421,7 @@
             }
         }
         Interpolator interpolator;
-        S state = mContainerInterface.stateFromGestureEndTarget(endTarget);
+        STATE state = mContainerInterface.stateFromGestureEndTarget(endTarget);
         if (isKeyboardTaskFocusPending()) {
             interpolator = EMPHASIZED;
         } else if (state.displayOverviewTasksAsGrid(mDp)) {
@@ -1757,8 +1771,7 @@
 
     private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget,
             RecentsOrientedState orientationState) {
-        if (runningTaskTarget.rotationChange != 0
-                && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+        if (runningTaskTarget.rotationChange != 0) {
             return Math.abs(runningTaskTarget.rotationChange) == ROTATION_90
                     ? ROTATION_270 : ROTATION_90;
         } else {
@@ -2357,7 +2370,7 @@
                     ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
                 }
                 ActiveGestureLog.INSTANCE.addLog(nextTaskLog);
-                nextTask.launchTask(success -> {
+                nextTask.launchWithoutAnimation(true, success -> {
                     resultCallback.accept(success);
                     if (success) {
                         if (hasTaskPreviouslyAppeared) {
@@ -2370,7 +2383,7 @@
                         }
                     }
                     return Unit.INSTANCE;
-                }, true /* freezeTaskList */);
+                }  /* freezeTaskList */);
             } else {
                 mContainerInterface.onLaunchTaskFailed();
                 Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
@@ -2489,7 +2502,7 @@
     }
 
     private void animateSplashScreenExit(
-            @NonNull T activity,
+            @NonNull RECENTS_CONTAINER activity,
             @NonNull RemoteAnimationTarget[] appearedTaskTargets,
             @NonNull RemoteAnimationTarget[] animatingTargets) {
         ViewGroup splashView = activity.getDragLayer();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 293944d..8703843 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -21,11 +21,13 @@
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_ATTACHED_ALPHA_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
 
 import android.animation.Animator;
@@ -187,8 +189,10 @@
          * @param attached Whether to show RecentsView alongside the app window. If false, recents
          *                 will be hidden by some property we can animate, e.g. alpha.
          * @param animate Whether to animate recents to/from its new attached state.
+         * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
          */
-        default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
+        default void setRecentsAttachedToAppWindow(
+                boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }
 
         default boolean isRecentsAttachedToAppWindow() {
             return false;
@@ -253,12 +257,14 @@
             // (because we set the animation as the current state animation), so we reapply the
             // attached state here as well to ensure recents is shown/hidden appropriately.
             if (DisplayController.getNavigationMode(mActivity) == NavigationMode.NO_BUTTON) {
-                setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
+                setRecentsAttachedToAppWindow(
+                        mIsAttachedToWindow, false, recentsView.shouldUpdateRunningTaskAlpha());
             }
         }
 
         @Override
-        public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
+        public void setRecentsAttachedToAppWindow(
+                boolean attached, boolean animate, boolean updateRunningTaskAlpha) {
             if (mIsAttachedToWindow == attached && animate) {
                 return;
             }
@@ -266,6 +272,10 @@
                     .cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM);
             mActivity.getStateManager()
                     .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+            if (updateRunningTaskAlpha) {
+                mActivity.getStateManager()
+                        .cancelStateElementAnimation(INDEX_RECENTS_ATTACHED_ALPHA_ANIM);
+            }
 
             AnimatorSet animatorSet = new AnimatorSet();
             animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -280,19 +290,28 @@
 
             long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0;
             Animator fadeAnim = mActivity.getStateManager()
-                    .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+                    .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1f : 0f);
             fadeAnim.setInterpolator(attached ? INSTANT : ACCELERATE_2);
             fadeAnim.setDuration(animationDuration);
             animatorSet.play(fadeAnim);
 
             float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
                     mActivity.getOverviewPanel());
-            float toTranslation = attached ? 0 : 1;
-
+            float toTranslation = attached ? 0f : 1f;
             Animator translationAnimator = mActivity.getStateManager().createStateElementAnimation(
                     INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
             translationAnimator.setDuration(animationDuration);
             animatorSet.play(translationAnimator);
+
+            if (updateRunningTaskAlpha) {
+                float fromAlpha = RUNNING_TASK_ATTACH_ALPHA.get(mActivity.getOverviewPanel());
+                float toAlpha = attached ? 1f : 0f;
+                Animator runningTaskAttachAlphaAnimator = mActivity.getStateManager()
+                        .createStateElementAnimation(
+                                INDEX_RECENTS_ATTACHED_ALPHA_ANIM, fromAlpha, toAlpha);
+                runningTaskAttachAlphaAnimator.setDuration(animationDuration);
+                animatorSet.play(runningTaskAttachAlphaAnimator);
+            }
             animatorSet.start();
         }
 
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 3a8c141..777761b 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -68,8 +68,6 @@
 
     public abstract void onAssistantVisibilityChanged(float assistantVisibility);
 
-    public abstract boolean allowMinimizeSplitScreen();
-
     public abstract boolean isResumed();
 
     public abstract boolean isStarted();
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index fbc0d14..94f4920 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,8 +24,8 @@
 import com.android.quickstep.views.RecentsView
 import com.android.quickstep.views.RecentsViewContainer
 import com.android.quickstep.views.TaskContainer
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
 
 /** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
 class DesktopSystemShortcut(
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
index 904ed69..e6822ff 100644
--- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -52,7 +52,11 @@
         )
 
     val lpnhTimeoutMs =
-        propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds")
+        propReader.get(
+            "LPNH_TIMEOUT_MS",
+            DEFAULT_LPNH_TIMEOUT_MS,
+            "Controls lpnh timeout in milliseconds"
+        )
 
     val lpnhSlopPercentage =
         propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh")
@@ -172,5 +176,7 @@
         @JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
 
         @JvmStatic fun get() = configHelper.config
+
+        const val DEFAULT_LPNH_TIMEOUT_MS = 450
     }
 }
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 89fbf4a..94a4527 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -133,12 +133,6 @@
     }
 
     @Override
-    public boolean allowMinimizeSplitScreen() {
-        // TODO: Remove this once b/77875376 is fixed
-        return false;
-    }
-
-    @Override
     public boolean allowAllAppsFromOverview() {
         return false;
     }
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index f898e2f..0185737 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -40,6 +40,7 @@
     int TYPE_STATUS_BAR = 1 << 13;
     int TYPE_CURSOR_HOVER = 1 << 14;
     int TYPE_NAV_HANDLE_LONG_PRESS = 1 << 15;
+    int TYPE_BUBBLE_BAR = 1 << 16;
 
     String[] NAMES = new String[] {
            "TYPE_NO_OP",                    // 0
@@ -58,6 +59,7 @@
             "TYPE_STATUS_BAR",              // 13
             "TYPE_CURSOR_HOVER",            // 14
             "TYPE_NAV_HANDLE_LONG_PRESS",   // 15
+            "TYPE_BUBBLE_BAR",              // 16
     };
 
     InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index b564fa7..e9fe2f7 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -271,11 +271,6 @@
     }
 
     @Override
-    public boolean allowMinimizeSplitScreen() {
-        return true;
-    }
-
-    @Override
     public boolean allowAllAppsFromOverview() {
         return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
                 // If floating search bar would not show in overview, don't allow all apps gesture.
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index b720382..a4ee3dd 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -341,7 +341,9 @@
         mTransaction
                 .setColor(mScrimLayer, colorComponents)
                 .setAlpha(mScrimLayer, mScrimAlpha)
-                .show(mScrimLayer);
+                .show(mScrimLayer)
+                // Ensure the scrim layer occludes opening task & wallpaper
+                .setLayer(mScrimLayer, 1000);
     }
 
     void removeScrimLayer() {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index e17cdcd..f653e60 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -62,8 +62,8 @@
 /**
  * Temporary class to allow easier refactoring
  */
-public class LauncherSwipeHandlerV2 extends
-        AbsSwipeUpHandler<QuickstepLauncher, RecentsView, LauncherState> {
+public class LauncherSwipeHandlerV2 extends AbsSwipeUpHandler<
+        QuickstepLauncher, RecentsView<QuickstepLauncher, LauncherState>, LauncherState> {
 
     public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
             TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
@@ -107,9 +107,6 @@
                 || !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
 
         mContainer.getRootView().setForceHideBackArrow(true);
-        if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            mContainer.setHintUserWillBeActive();
-        }
 
         if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
             return new LauncherHomeAnimationFactory() {
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 84f6b55..a03c0f8 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.systemui.shared.Flags;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
@@ -242,7 +243,8 @@
         int rotation = display.rotation;
         int touchHeight = mNavBarGesturalHeight;
         OrientationRectF orientationRectF = new OrientationRectF(0, 0, size.x, size.y, rotation);
-        if (mMode == NavigationMode.NO_BUTTON) {
+        if (mMode == NavigationMode.NO_BUTTON
+                || (mMode == NavigationMode.THREE_BUTTONS && Flags.threeButtonCornerSwipe())) {
             orientationRectF.top = orientationRectF.bottom - touchHeight;
             updateAssistantRegions(orientationRectF);
         } else {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
deleted file mode 100644
index 8f533a3..0000000
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2018 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;
-
-import static com.android.launcher3.PagedView.INVALID_PAGE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Intent;
-import android.graphics.PointF;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
-import com.android.internal.jank.Cuj;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.taskbar.TaskbarUIController;
-import com.android.launcher3.util.RunnableList;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
-import com.android.quickstep.util.ActiveGestureLog;
-import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Helper class to handle various atomic commands for switching between Overview.
- */
-public class OverviewCommandHelper {
-    private static final String TAG = "OverviewCommandHelper";
-
-    public static final int TYPE_SHOW = 1;
-    public static final int TYPE_KEYBOARD_INPUT = 2;
-    public static final int TYPE_HIDE = 3;
-    public static final int TYPE_TOGGLE = 4;
-    public static final int TYPE_HOME = 5;
-
-    /**
-     * Use case for needing a queue is double tapping recents button in 3 button nav.
-     * Size of 2 should be enough. We'll toss in one more because we're kind hearted.
-     */
-    private final static int MAX_QUEUE_SIZE = 3;
-
-    private static final String TRANSITION_NAME = "Transition:toOverview";
-
-    private final TouchInteractionService mService;
-    private final OverviewComponentObserver mOverviewComponentObserver;
-    private final TaskAnimationManager mTaskAnimationManager;
-    private final ArrayList<CommandInfo> mPendingCommands = new ArrayList<>();
-
-    /**
-     * Index of the TaskView that should be focused when launching Overview. Persisted so that we
-     * do not lose the focus across multiple calls of
-     * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
-     */
-    private int mKeyboardTaskFocusIndex = -1;
-
-    /**
-     * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
-     * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
-     * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
-     * janky recents animations and unresponsive home and overview buttons.
-     */
-    private boolean mWaitForToggleCommandComplete = false;
-
-    public OverviewCommandHelper(TouchInteractionService service,
-            OverviewComponentObserver observer,
-            TaskAnimationManager taskAnimationManager) {
-        mService = service;
-        mOverviewComponentObserver = observer;
-        mTaskAnimationManager = taskAnimationManager;
-    }
-
-    /**
-     * Called when the command finishes execution.
-     */
-    private void scheduleNextTask(CommandInfo command) {
-        if (mPendingCommands.isEmpty()) {
-            Log.d(TAG, "no pending commands to schedule");
-            return;
-        }
-        if (mPendingCommands.get(0) != command) {
-            Log.d(TAG, "next task not scheduled."
-                    + " mPendingCommands[0] type is " + mPendingCommands.get(0)
-                    + " - command type is: " + command);
-            return;
-        }
-        Log.d(TAG, "scheduleNextTask called: " + command);
-        mPendingCommands.remove(0);
-        executeNext();
-    }
-
-    /**
-     * Executes the next command from the queue. If the command finishes immediately (returns true),
-     * it continues to execute the next command, until the queue is empty of a command defer's its
-     * completion (returns false).
-     */
-    @UiThread
-    private void executeNext() {
-        if (mPendingCommands.isEmpty()) {
-            Log.d(TAG, "executeNext - mPendingCommands is empty");
-            return;
-        }
-        CommandInfo cmd = mPendingCommands.get(0);
-
-        boolean result = executeCommand(cmd);
-        Log.d(TAG, "executeNext cmd type: " + cmd + ", result: " + result);
-        if (result) {
-            scheduleNextTask(cmd);
-        }
-    }
-
-    @UiThread
-    private void addCommand(CommandInfo cmd) {
-        boolean wasEmpty = mPendingCommands.isEmpty();
-        mPendingCommands.add(cmd);
-        if (wasEmpty) {
-            executeNext();
-        }
-    }
-
-    /**
-     * Adds a command to be executed next, after all pending tasks are completed.
-     * Max commands that can be queued is {@link #MAX_QUEUE_SIZE}.
-     * Requests after reaching that limit will be silently dropped.
-     */
-    @BinderThread
-    public void addCommand(int type) {
-        if (mPendingCommands.size() >= MAX_QUEUE_SIZE) {
-            Log.d(TAG, "the pending command queue is full (" + mPendingCommands.size() + "). "
-                    + "command not added: " + type);
-            return;
-        }
-        Log.d(TAG, "adding command type: " + type);
-        CommandInfo cmd = new CommandInfo(type);
-        MAIN_EXECUTOR.execute(() -> addCommand(cmd));
-    }
-
-    @UiThread
-    public void clearPendingCommands() {
-        Log.d(TAG, "clearing pending commands - size: " + mPendingCommands.size());
-        mPendingCommands.clear();
-    }
-
-    @UiThread
-    public boolean canStartHomeSafely() {
-        return mPendingCommands.isEmpty() || mPendingCommands.get(0).type == TYPE_HOME;
-    }
-
-    @Nullable
-    private TaskView getNextTask(RecentsView view) {
-        final TaskView runningTaskView = view.getRunningTaskView();
-
-        if (runningTaskView == null) {
-            return view.getTaskViewAt(0);
-        } else {
-            final TaskView nextTask = view.getNextTaskView();
-            return nextTask != null ? nextTask : runningTaskView;
-        }
-    }
-
-    private boolean launchTask(RecentsView recents, @Nullable TaskView taskView, CommandInfo cmd) {
-        RunnableList callbackList = null;
-        if (taskView != null) {
-            mWaitForToggleCommandComplete = true;
-            taskView.setEndQuickSwitchCuj(true);
-            callbackList = taskView.launchTasks();
-        }
-
-        if (callbackList != null) {
-            callbackList.add(() -> {
-                Log.d(TAG, "launching task callback: " + cmd);
-                scheduleNextTask(cmd);
-                mWaitForToggleCommandComplete = false;
-            });
-            Log.d(TAG, "launching task - waiting for callback: " + cmd);
-            return false;
-        } else {
-            recents.startHome();
-            mWaitForToggleCommandComplete = false;
-            return true;
-        }
-    }
-
-    /**
-     * Executes the task and returns true if next task can be executed. If false, then the next
-     * task is deferred until {@link #scheduleNextTask} is called
-     */
-    private <T extends StatefulActivity<?> & RecentsViewContainer> boolean executeCommand(
-            CommandInfo cmd) {
-        if (mWaitForToggleCommandComplete && cmd.type == TYPE_TOGGLE) {
-            Log.d(TAG, "executeCommand: " + cmd
-                    + " - waiting for toggle command complete");
-            return true;
-        }
-        BaseActivityInterface<?, T> activityInterface =
-                mOverviewComponentObserver.getActivityInterface();
-
-        RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
-        RecentsView<?, ?> createdRecentsView;
-
-        Log.d(TAG, "executeCommand: " + cmd
-                + " - visibleRecentsView: " + visibleRecentsView);
-        if (visibleRecentsView == null) {
-            T activity = activityInterface.getCreatedContainer();
-            createdRecentsView = activity == null ? null : activity.getOverviewPanel();
-            DeviceProfile dp = activity == null ? null : activity.getDeviceProfile();
-            TaskbarUIController uiController = activityInterface.getTaskbarController();
-            boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
-                    && uiController != null
-                    && dp != null
-                    && (dp.isTablet || dp.isTwoPanels);
-
-            switch (cmd.type) {
-                case TYPE_HIDE:
-                    if (!allowQuickSwitch) {
-                        return true;
-                    }
-                    mKeyboardTaskFocusIndex = uiController.launchFocusedTask();
-                    if (mKeyboardTaskFocusIndex == -1) {
-                        return true;
-                    }
-                    break;
-                case TYPE_KEYBOARD_INPUT:
-                    if (allowQuickSwitch) {
-                        uiController.openQuickSwitchView();
-                        return true;
-                    } else {
-                        mKeyboardTaskFocusIndex = 0;
-                        break;
-                    }
-                case TYPE_HOME:
-                    ActiveGestureLog.INSTANCE.addLog(
-                            "OverviewCommandHelper.executeCommand(TYPE_HOME)");
-                    // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
-                    // we should still call it on main thread because launcher is waiting for
-                    // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
-                    // could potentially delay resuming launcher. See b/348668521 for more details.
-                    mService.startActivity(mOverviewComponentObserver.getHomeIntent());
-                    return true;
-                case TYPE_SHOW:
-                    // When Recents is not currently visible, the command's type is TYPE_SHOW
-                    // when overview is triggered via the keyboard overview button or Action+Tab
-                    // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
-                    // nav is TYPE_TOGGLE.
-                    mKeyboardTaskFocusIndex = 0;
-                    break;
-                default:
-                    // continue below to handle displaying Recents.
-            }
-        } else {
-            createdRecentsView = visibleRecentsView;
-            switch (cmd.type) {
-                case TYPE_SHOW:
-                    // already visible
-                    return true;
-                case TYPE_KEYBOARD_INPUT: {
-                    if (visibleRecentsView.isHandlingTouch()) {
-                        return true;
-                    }
-                }
-                case TYPE_HIDE: {
-                    if (visibleRecentsView.isHandlingTouch()) {
-                        return true;
-                    }
-                    mKeyboardTaskFocusIndex = INVALID_PAGE;
-                    int currentPage = visibleRecentsView.getNextPage();
-                    TaskView tv = (currentPage >= 0
-                            && currentPage < visibleRecentsView.getTaskViewCount())
-                            ? (TaskView) visibleRecentsView.getPageAt(currentPage)
-                            : null;
-                    return launchTask(visibleRecentsView, tv, cmd);
-                }
-                case TYPE_TOGGLE:
-                    return launchTask(visibleRecentsView, getNextTask(visibleRecentsView), cmd);
-                case TYPE_HOME:
-                    visibleRecentsView.startHome();
-                    return true;
-            }
-        }
-
-        if (createdRecentsView != null) {
-            createdRecentsView.setKeyboardTaskFocusIndex(mKeyboardTaskFocusIndex);
-        }
-        // Handle recents view focus when launching from home
-        Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                super.onAnimationStart(animation);
-                updateRecentsViewFocus(cmd);
-                logShowOverviewFrom(cmd.type);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                Log.d(TAG, "switching to Overview state - onAnimationEnd: " + cmd);
-                super.onAnimationEnd(animation);
-                onRecentsViewFocusUpdated(cmd);
-                scheduleNextTask(cmd);
-            }
-        };
-        if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
-            Log.d(TAG, "switching to Overview state - waiting: " + cmd);
-            // If successfully switched, wait until animation finishes
-            return false;
-        }
-
-        final T activity = activityInterface.getCreatedContainer();
-        if (activity != null) {
-            InteractionJankMonitorWrapper.begin(
-                    activity.getRootView(),
-                    Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
-        }
-
-        GestureState gestureState = mService.createGestureState(GestureState.DEFAULT_STATE,
-                GestureState.TrackpadGestureType.NONE);
-        gestureState.setHandlingAtomicEvent(true);
-        AbsSwipeUpHandler interactionHandler = mService.getSwipeUpHandlerFactory()
-                .newHandler(gestureState, cmd.createTime);
-        interactionHandler.setGestureEndCallback(
-                () -> onTransitionComplete(cmd, interactionHandler));
-        interactionHandler.initWhenReady("OverviewCommandHelper: cmd.type=" + cmd.type);
-
-        RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() {
-            @Override
-            public void onRecentsAnimationStart(RecentsAnimationController controller,
-                    RecentsAnimationTargets targets) {
-                updateRecentsViewFocus(cmd);
-                logShowOverviewFrom(cmd.type);
-                activityInterface.runOnInitBackgroundStateUI(() ->
-                        interactionHandler.onGestureEnded(0, new PointF()));
-                cmd.removeListener(this);
-            }
-
-            @Override
-            public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
-                interactionHandler.onGestureCancelled();
-                cmd.removeListener(this);
-
-                T createdActivity = activityInterface.getCreatedContainer();
-                if (createdActivity == null) {
-                    return;
-                }
-                if (createdRecentsView != null) {
-                    createdRecentsView.onRecentsAnimationComplete();
-                }
-            }
-        };
-
-        if (visibleRecentsView != null) {
-            visibleRecentsView.moveRunningTaskToFront();
-        }
-        if (mTaskAnimationManager.isRecentsAnimationRunning()) {
-            cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState);
-            cmd.mActiveCallbacks.addListener(interactionHandler);
-            mTaskAnimationManager.notifyRecentsAnimationState(interactionHandler);
-            interactionHandler.onGestureStarted(true /*isLikelyToStartNewTask*/);
-
-            cmd.mActiveCallbacks.addListener(recentAnimListener);
-            mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener);
-        } else {
-            Intent intent = new Intent(interactionHandler.getLaunchIntent());
-            intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId());
-            cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(
-                    gestureState, intent, interactionHandler);
-            interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/);
-            cmd.mActiveCallbacks.addListener(recentAnimListener);
-        }
-        Trace.beginAsyncSection(TRANSITION_NAME, 0);
-        Log.d(TAG, "switching via recents animation - onGestureStarted: " + cmd);
-        return false;
-    }
-
-    private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) {
-        Log.d(TAG, "switching via recents animation - onTransitionComplete: " + cmd);
-        cmd.removeListener(handler);
-        Trace.endAsyncSection(TRANSITION_NAME, 0);
-        onRecentsViewFocusUpdated(cmd);
-        scheduleNextTask(cmd);
-    }
-
-    private void updateRecentsViewFocus(CommandInfo cmd) {
-        RecentsView recentsView =
-                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
-        if (recentsView == null || (cmd.type != TYPE_KEYBOARD_INPUT && cmd.type != TYPE_HIDE
-                && cmd.type != TYPE_SHOW)) {
-            return;
-        }
-        // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
-        // the touch mode somehow is not change to false by the Android framework.
-        // The subsequent tab to go through tasks in overview can only be dispatched to
-        // focuses views, while focus can only be requested in
-        // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
-        // here we launch overview with live tile.
-        recentsView.getViewRootImpl().touchModeChanged(false);
-        // Ensure that recents view has focus so that it receives the followup key inputs
-        if (requestFocus(recentsView.getTaskViewAt(mKeyboardTaskFocusIndex))) {
-            return;
-        }
-        if (requestFocus(recentsView.getNextTaskView())) {
-            return;
-        }
-        if (requestFocus(recentsView.getTaskViewAt(0))) {
-            return;
-        }
-        requestFocus(recentsView);
-    }
-
-    private void onRecentsViewFocusUpdated(CommandInfo cmd) {
-        RecentsView recentsView =
-                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
-        if (recentsView == null
-                || cmd.type != TYPE_HIDE
-                || mKeyboardTaskFocusIndex == INVALID_PAGE) {
-            return;
-        }
-        recentsView.setKeyboardTaskFocusIndex(INVALID_PAGE);
-        recentsView.setCurrentPage(mKeyboardTaskFocusIndex);
-        mKeyboardTaskFocusIndex = INVALID_PAGE;
-    }
-
-    private boolean requestFocus(@Nullable View taskView) {
-        if (taskView == null) {
-            return false;
-        }
-        taskView.post(() -> {
-            taskView.requestFocus();
-            taskView.requestAccessibilityFocus();
-        });
-        return true;
-    }
-
-    private <T extends StatefulActivity<?> & RecentsViewContainer>
-            void logShowOverviewFrom(int cmdType) {
-        BaseActivityInterface<?, T> activityInterface =
-                mOverviewComponentObserver.getActivityInterface();
-        var container = activityInterface.getCreatedContainer();
-        if (container != null) {
-            StatsLogManager.LauncherEvent event;
-            switch (cmdType) {
-                case TYPE_SHOW -> event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT;
-                case TYPE_HIDE ->
-                        event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH;
-                case TYPE_TOGGLE -> event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON;
-                default -> {
-                    return;
-                }
-            }
-
-            StatsLogManager.newInstance(container.asContext())
-                    .logger()
-                    .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
-                            .setTaskSwitcherContainer(
-                                    LauncherAtom.TaskSwitcherContainer.getDefaultInstance())
-                            .build())
-                    .log(event);
-        }
-    }
-
-    public void dump(PrintWriter pw) {
-        pw.println("OverviewCommandHelper:");
-        pw.println("  mPendingCommands=" + mPendingCommands.size());
-        if (!mPendingCommands.isEmpty()) {
-            pw.println("    pendingCommandType=" + mPendingCommands.get(0).type);
-        }
-        pw.println("  mKeyboardTaskFocusIndex=" + mKeyboardTaskFocusIndex);
-        pw.println("  mWaitForToggleCommandComplete=" + mWaitForToggleCommandComplete);
-    }
-
-    private static class CommandInfo {
-        public final long createTime = SystemClock.elapsedRealtime();
-        public final int type;
-        RecentsAnimationCallbacks mActiveCallbacks;
-
-        CommandInfo(int type) {
-            this.type = type;
-        }
-
-        void removeListener(RecentsAnimationListener listener) {
-            if (mActiveCallbacks != null) {
-                mActiveCallbacks.removeListener(listener);
-            }
-        }
-
-        @NonNull
-        @Override
-        public String toString() {
-            return "CommandInfo("
-                    + "type=" + type + ", "
-                    + "createTime=" + createTime + ", "
-                    + "mActiveCallbacks=" + mActiveCallbacks
-                    + ")";
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
new file mode 100644
index 0000000..c1f9963
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2018 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
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.content.Intent
+import android.graphics.PointF
+import android.os.SystemClock
+import android.os.Trace
+import android.util.Log
+import android.view.View
+import androidx.annotation.BinderThread
+import androidx.annotation.UiThread
+import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.Cuj
+import com.android.launcher3.Flags.enableOverviewCommandHelperTimeout
+import com.android.launcher3.PagedView
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.coroutines.DispatcherProvider
+import com.android.launcher3.util.coroutines.ProductionDispatchers
+import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus
+import com.android.quickstep.OverviewCommandHelper.CommandType.HIDE
+import com.android.quickstep.OverviewCommandHelper.CommandType.HOME
+import com.android.quickstep.OverviewCommandHelper.CommandType.KEYBOARD_INPUT
+import com.android.quickstep.OverviewCommandHelper.CommandType.SHOW
+import com.android.quickstep.OverviewCommandHelper.CommandType.TOGGLE
+import com.android.quickstep.util.ActiveGestureLog
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper
+import java.io.PrintWriter
+import java.util.concurrent.ConcurrentLinkedDeque
+import kotlin.coroutines.resume
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.ensureActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withTimeout
+
+/** Helper class to handle various atomic commands for switching between Overview. */
+class OverviewCommandHelper
+@JvmOverloads
+constructor(
+    private val touchInteractionService: TouchInteractionService,
+    private val overviewComponentObserver: OverviewComponentObserver,
+    private val taskAnimationManager: TaskAnimationManager,
+    private val dispatcherProvider: DispatcherProvider = ProductionDispatchers,
+) {
+    private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.default)
+
+    private val commandQueue = ConcurrentLinkedDeque<CommandInfo>()
+
+    /**
+     * Index of the TaskView that should be focused when launching Overview. Persisted so that we do
+     * not lose the focus across multiple calls of [OverviewCommandHelper.executeCommand] for the
+     * same command
+     */
+    private var keyboardTaskFocusIndex = -1
+
+    /**
+     * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
+     * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
+     * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
+     * janky recents animations and unresponsive home and overview buttons.
+     */
+    private var waitForToggleCommandComplete = false
+
+    private val activityInterface: BaseActivityInterface<*, *>
+        get() = overviewComponentObserver.activityInterface
+
+    private val visibleRecentsView: RecentsView<*, *>?
+        get() = activityInterface.getVisibleRecentsView<RecentsView<*, *>>()
+
+    /**
+     * Adds a command to be executed next, after all pending tasks are completed. Max commands that
+     * can be queued is [.MAX_QUEUE_SIZE]. Requests after reaching that limit will be silently
+     * dropped.
+     */
+    @BinderThread
+    fun addCommand(type: CommandType): CommandInfo? {
+        if (commandQueue.size >= MAX_QUEUE_SIZE) {
+            Log.d(TAG, "command not added: $type - queue is full ($commandQueue).")
+            return null
+        }
+
+        val command = CommandInfo(type)
+        commandQueue.add(command)
+        Log.d(TAG, "command added: $command")
+
+        if (commandQueue.size == 1) {
+            Log.d(TAG, "execute: $command - queue size: ${commandQueue.size}")
+            if (enableOverviewCommandHelperTimeout()) {
+                coroutineScope.launch(dispatcherProvider.main) { processNextCommand() }
+            } else {
+                Executors.MAIN_EXECUTOR.execute { processNextCommand() }
+            }
+        } else {
+            Log.d(TAG, "not executed: $command - queue size: ${commandQueue.size}")
+        }
+
+        return command
+    }
+
+    fun canStartHomeSafely(): Boolean = commandQueue.isEmpty() || commandQueue.first().type == HOME
+
+    /** Clear pending or completed commands from the queue */
+    fun clearPendingCommands() {
+        Log.d(TAG, "clearing pending commands: $commandQueue")
+        commandQueue.removeAll { it.status != CommandStatus.PROCESSING }
+    }
+
+    /**
+     * Executes the next command from the queue. If the command finishes immediately (returns true),
+     * it continues to execute the next command, until the queue is empty of a command defer's its
+     * completion (returns false).
+     */
+    @UiThread
+    private fun processNextCommand() {
+        val command: CommandInfo =
+            commandQueue.firstOrNull()
+                ?: run {
+                    Log.d(TAG, "no pending commands to be executed.")
+                    return
+                }
+
+        command.status = CommandStatus.PROCESSING
+        Log.d(TAG, "executing command: $command")
+
+        if (enableOverviewCommandHelperTimeout()) {
+            coroutineScope.launch(dispatcherProvider.main) {
+                withTimeout(QUEUE_WAIT_DURATION_IN_MS) {
+                    executeCommandSuspended(command)
+                    ensureActive()
+                    onCommandFinished(command)
+                }
+            }
+        } else {
+            val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) })
+            Log.d(TAG, "command executed: $command with result: $result")
+            if (result) {
+                onCommandFinished(command)
+            } else {
+                Log.d(TAG, "waiting for command callback: $command")
+            }
+        }
+    }
+
+    /**
+     * Executes the task and returns true if next task can be executed. If false, then the next task
+     * is deferred until [.scheduleNextTask] is called
+     */
+    @VisibleForTesting
+    fun executeCommand(command: CommandInfo, onCallbackResult: () -> Unit): Boolean {
+        // This shouldn't happen if we execute 1 command per time.
+        if (waitForToggleCommandComplete && command.type == TOGGLE) {
+            Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
+            return true
+        }
+
+        val recentsView = visibleRecentsView
+        Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView")
+        return if (recentsView != null) {
+            executeWhenRecentsIsVisible(command, recentsView, onCallbackResult)
+        } else {
+            executeWhenRecentsIsNotVisible(command, onCallbackResult)
+        }
+    }
+
+    /**
+     * Executes the task and returns true if next task can be executed. If false, then the next task
+     * is deferred until [.scheduleNextTask] is called
+     */
+    private suspend fun executeCommandSuspended(command: CommandInfo) =
+        suspendCancellableCoroutine { continuation ->
+            fun processResult(isCompleted: Boolean) {
+                Log.d(TAG, "command executed: $command with result: $isCompleted")
+                if (isCompleted) {
+                    continuation.resume(Unit)
+                } else {
+                    Log.d(TAG, "waiting for command callback: $command")
+                }
+            }
+
+            val result = executeCommand(command, onCallbackResult = { processResult(true) })
+            processResult(result)
+
+            continuation.invokeOnCancellation { cancelCommand(command, it) }
+        }
+
+    private fun executeWhenRecentsIsVisible(
+        command: CommandInfo,
+        recentsView: RecentsView<*, *>,
+        onCallbackResult: () -> Unit,
+    ): Boolean =
+        when (command.type) {
+            SHOW -> true // already visible
+            KEYBOARD_INPUT,
+            HIDE -> {
+                if (recentsView.isHandlingTouch) {
+                    true
+                } else {
+                    keyboardTaskFocusIndex = PagedView.INVALID_PAGE
+                    val currentPage = recentsView.nextPage
+                    val taskView = recentsView.getTaskViewAt(currentPage)
+                    launchTask(recentsView, taskView, command, onCallbackResult)
+                }
+            }
+            TOGGLE -> {
+                val taskView =
+                    if (recentsView.runningTaskView == null) {
+                        recentsView.getTaskViewAt(0)
+                    } else {
+                        recentsView.nextTaskView ?: recentsView.runningTaskView
+                    }
+                launchTask(recentsView, taskView, command, onCallbackResult)
+            }
+            HOME -> {
+                recentsView.startHome()
+                true
+            }
+        }
+
+    private fun launchTask(
+        recents: RecentsView<*, *>,
+        taskView: TaskView?,
+        command: CommandInfo,
+        onCallbackResult: () -> Unit
+    ): Boolean {
+        var callbackList: RunnableList? = null
+        if (taskView != null) {
+            waitForToggleCommandComplete = true
+            taskView.isEndQuickSwitchCuj = true
+            callbackList = taskView.launchWithAnimation()
+        }
+
+        if (callbackList != null) {
+            callbackList.add {
+                Log.d(TAG, "launching task callback: $command")
+                onCallbackResult()
+                waitForToggleCommandComplete = false
+            }
+            Log.d(TAG, "launching task - waiting for callback: $command")
+            return false
+        } else {
+            recents.startHome()
+            waitForToggleCommandComplete = false
+            return true
+        }
+    }
+
+    private fun executeWhenRecentsIsNotVisible(
+        command: CommandInfo,
+        onCallbackResult: () -> Unit
+    ): Boolean {
+        val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer
+        val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel()
+        val deviceProfile = recentsViewContainer?.getDeviceProfile()
+        val uiController = activityInterface.getTaskbarController()
+        val allowQuickSwitch =
+            FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() &&
+                uiController != null &&
+                deviceProfile != null &&
+                (deviceProfile.isTablet || deviceProfile.isTwoPanels)
+
+        when (command.type) {
+            HIDE -> {
+                if (!allowQuickSwitch) return true
+                keyboardTaskFocusIndex = uiController!!.launchFocusedTask()
+                if (keyboardTaskFocusIndex == -1) return true
+            }
+            KEYBOARD_INPUT ->
+                if (allowQuickSwitch) {
+                    uiController!!.openQuickSwitchView()
+                    return true
+                } else {
+                    keyboardTaskFocusIndex = 0
+                }
+            HOME -> {
+                ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(HOME)")
+                // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
+                // we should still call it on main thread because launcher is waiting for
+                // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
+                // could potentially delay resuming launcher. See b/348668521 for more details.
+                touchInteractionService.startActivity(overviewComponentObserver.homeIntent)
+                return true
+            }
+            SHOW ->
+                // When Recents is not currently visible, the command's type is SHOW
+                // when overview is triggered via the keyboard overview button or Action+Tab
+                // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
+                // nav is TYPE_TOGGLE.
+                keyboardTaskFocusIndex = 0
+            TOGGLE -> {}
+        }
+
+        recentsView?.setKeyboardTaskFocusIndex(keyboardTaskFocusIndex)
+        // Handle recents view focus when launching from home
+        val animatorListener: Animator.AnimatorListener =
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationStart(animation: Animator) {
+                    Log.d(TAG, "switching to Overview state - onAnimationStart: $command")
+                    super.onAnimationStart(animation)
+                    updateRecentsViewFocus(command)
+                    logShowOverviewFrom(command.type)
+                }
+
+                override fun onAnimationEnd(animation: Animator) {
+                    Log.d(TAG, "switching to Overview state - onAnimationEnd: $command")
+                    super.onAnimationEnd(animation)
+                    onRecentsViewFocusUpdated(command)
+                    onCallbackResult()
+                }
+            }
+        if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
+            Log.d(TAG, "switching to Overview state - waiting: $command")
+            // If successfully switched, wait until animation finishes
+            return false
+        }
+
+        val activity = activityInterface.getCreatedContainer()
+        if (activity != null) {
+            InteractionJankMonitorWrapper.begin(activity.rootView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH)
+        }
+
+        val gestureState =
+            touchInteractionService.createGestureState(
+                GestureState.DEFAULT_STATE,
+                GestureState.TrackpadGestureType.NONE
+            )
+        gestureState.isHandlingAtomicEvent = true
+        val interactionHandler =
+            touchInteractionService.swipeUpHandlerFactory.newHandler(
+                gestureState,
+                command.createTime
+            )
+        interactionHandler.setGestureEndCallback {
+            onTransitionComplete(command, interactionHandler, onCallbackResult)
+        }
+        interactionHandler.initWhenReady("OverviewCommandHelper: command.type=${command.type}")
+
+        val recentAnimListener: RecentsAnimationCallbacks.RecentsAnimationListener =
+            object : RecentsAnimationCallbacks.RecentsAnimationListener {
+                override fun onRecentsAnimationStart(
+                    controller: RecentsAnimationController,
+                    targets: RecentsAnimationTargets
+                ) {
+                    Log.d(TAG, "recents animation started: $command")
+                    updateRecentsViewFocus(command)
+                    logShowOverviewFrom(command.type)
+                    activityInterface.runOnInitBackgroundStateUI {
+                        Log.d(TAG, "recents animation started - onInitBackgroundStateUI: $command")
+                        interactionHandler.onGestureEnded(0f, PointF())
+                    }
+                    command.removeListener(this)
+                }
+
+                override fun onRecentsAnimationCanceled(
+                    thumbnailDatas: HashMap<Int, ThumbnailData>
+                ) {
+                    Log.d(TAG, "recents animation canceled: $command")
+                    interactionHandler.onGestureCancelled()
+                    command.removeListener(this)
+
+                    activityInterface.getCreatedContainer() ?: return
+                    recentsView?.onRecentsAnimationComplete()
+                }
+            }
+
+        if (taskAnimationManager.isRecentsAnimationRunning) {
+            command.setAnimationCallbacks(
+                taskAnimationManager.continueRecentsAnimation(gestureState)
+            )
+            command.addListener(interactionHandler)
+            taskAnimationManager.notifyRecentsAnimationState(interactionHandler)
+            interactionHandler.onGestureStarted(true /*isLikelyToStartNewTask*/)
+
+            command.addListener(recentAnimListener)
+            taskAnimationManager.notifyRecentsAnimationState(recentAnimListener)
+        } else {
+            val intent =
+                Intent(interactionHandler.getLaunchIntent())
+                    .putExtra(ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID, gestureState.gestureId)
+            command.setAnimationCallbacks(
+                taskAnimationManager.startRecentsAnimation(gestureState, intent, interactionHandler)
+            )
+            interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/)
+            command.addListener(recentAnimListener)
+        }
+        Trace.beginAsyncSection(TRANSITION_NAME, 0)
+        Log.d(TAG, "switching via recents animation - onGestureStarted: $command")
+        return false
+    }
+
+    private fun onTransitionComplete(
+        command: CommandInfo,
+        handler: AbsSwipeUpHandler<*, *, *>,
+        onCommandResult: () -> Unit
+    ) {
+        Log.d(TAG, "switching via recents animation - onTransitionComplete: $command")
+        command.removeListener(handler)
+        Trace.endAsyncSection(TRANSITION_NAME, 0)
+        onRecentsViewFocusUpdated(command)
+        onCommandResult()
+    }
+
+    /** Called when the command finishes execution. */
+    private fun onCommandFinished(command: CommandInfo) {
+        command.status = CommandStatus.COMPLETED
+        if (commandQueue.firstOrNull() !== command) {
+            Log.d(
+                TAG,
+                "next task not scheduled. First pending command type " +
+                    "is ${commandQueue.firstOrNull()} - command type is: $command"
+            )
+            return
+        }
+
+        Log.d(TAG, "command executed successfully! $command")
+        commandQueue.remove(command)
+        processNextCommand()
+    }
+
+    private fun cancelCommand(command: CommandInfo, throwable: Throwable?) {
+        command.status = CommandStatus.CANCELED
+        Log.e(TAG, "command cancelled: $command - $throwable")
+        commandQueue.remove(command)
+        processNextCommand()
+    }
+
+    private fun updateRecentsViewFocus(command: CommandInfo) {
+        val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+        if (command.type != KEYBOARD_INPUT && command.type != HIDE && command.type != SHOW) {
+            return
+        }
+
+        // When the overview is launched via alt tab (command type is TYPE_KEYBOARD_INPUT),
+        // the touch mode somehow is not change to false by the Android framework.
+        // The subsequent tab to go through tasks in overview can only be dispatched to
+        // focuses views, while focus can only be requested in
+        // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
+        // here we launch overview with live tile.
+        recentsView.viewRootImpl.touchModeChanged(false)
+        // Ensure that recents view has focus so that it receives the followup key inputs
+        // Stops requesting focused after first view gets focused.
+        recentsView.getTaskViewAt(keyboardTaskFocusIndex).requestFocus() ||
+            recentsView.nextTaskView.requestFocus() ||
+            recentsView.getTaskViewAt(0).requestFocus() ||
+            recentsView.requestFocus()
+    }
+
+    private fun onRecentsViewFocusUpdated(command: CommandInfo) {
+        val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+        if (command.type != HIDE || keyboardTaskFocusIndex == PagedView.INVALID_PAGE) {
+            return
+        }
+        recentsView.setKeyboardTaskFocusIndex(PagedView.INVALID_PAGE)
+        recentsView.currentPage = keyboardTaskFocusIndex
+        keyboardTaskFocusIndex = PagedView.INVALID_PAGE
+    }
+
+    private fun View?.requestFocus(): Boolean {
+        if (this == null) return false
+        post {
+            requestFocus()
+            requestAccessibilityFocus()
+        }
+        return true
+    }
+
+    private fun logShowOverviewFrom(commandType: CommandType) {
+        val container = activityInterface.getCreatedContainer() as? RecentsViewContainer ?: return
+        val event =
+            when (commandType) {
+                SHOW -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
+                HIDE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
+                TOGGLE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
+                else -> return
+            }
+        StatsLogManager.newInstance(container.asContext())
+            .logger()
+            .withContainerInfo(
+                LauncherAtom.ContainerInfo.newBuilder()
+                    .setTaskSwitcherContainer(
+                        LauncherAtom.TaskSwitcherContainer.getDefaultInstance()
+                    )
+                    .build()
+            )
+            .log(event)
+    }
+
+    fun dump(pw: PrintWriter) {
+        pw.println("OverviewCommandHelper:")
+        pw.println("  pendingCommands=${commandQueue.size}")
+        if (commandQueue.isNotEmpty()) {
+            pw.println("    pendingCommandType=${commandQueue.first().type}")
+        }
+        pw.println("  keyboardTaskFocusIndex=$keyboardTaskFocusIndex")
+        pw.println("  waitForToggleCommandComplete=$waitForToggleCommandComplete")
+    }
+
+    @VisibleForTesting
+    data class CommandInfo(
+        val type: CommandType,
+        var status: CommandStatus = CommandStatus.IDLE,
+        val createTime: Long = SystemClock.elapsedRealtime(),
+        private var animationCallbacks: RecentsAnimationCallbacks? = null
+    ) {
+        fun setAnimationCallbacks(recentsAnimationCallbacks: RecentsAnimationCallbacks) {
+            this.animationCallbacks = recentsAnimationCallbacks
+        }
+
+        fun addListener(listener: RecentsAnimationCallbacks.RecentsAnimationListener) {
+            animationCallbacks?.addListener(listener)
+        }
+
+        fun removeListener(listener: RecentsAnimationCallbacks.RecentsAnimationListener?) {
+            animationCallbacks?.removeListener(listener)
+        }
+
+        enum class CommandStatus {
+            IDLE,
+            PROCESSING,
+            COMPLETED,
+            CANCELED
+        }
+    }
+
+    enum class CommandType {
+        SHOW,
+        KEYBOARD_INPUT,
+        HIDE,
+        TOGGLE, // Navigate to Overview
+        HOME, // Navigate to Home
+    }
+
+    companion object {
+        private const val TAG = "OverviewCommandHelper"
+        private const val TRANSITION_NAME = "Transition:toOverview"
+
+        /**
+         * Use case for needing a queue is double tapping recents button in 3 button nav. Size of 2
+         * should be enough. We'll toss in one more because we're kind hearted.
+         */
+        private const val MAX_QUEUE_SIZE = 3
+        private const val QUEUE_WAIT_DURATION_IN_MS = 5000L
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index b290f83..49b6f57 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -1,16 +1,12 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.taskbar.TaskbarThresholdUtils.getFromNavThreshold;
-import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
 import android.os.Bundle;
-import android.util.Log;
 
 import androidx.annotation.Nullable;
 
@@ -18,7 +14,6 @@
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TISBindHelper;
@@ -82,29 +77,10 @@
             }
 
             case TestProtocol.REQUEST_GET_OVERVIEW_TASK_SIZE: {
-                Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH, "== REQUEST_GET_OVERVIEW_TASK_SIZE ==");
-                Rect gridSize = new Rect();
-                LauncherActivityInterface.INSTANCE.calculateGridSize(mDeviceProfile, mContext,
-                        gridSize);
-                Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH, "gridSize: " + gridSize);
-                PointF taskDimension = new PointF();
-                LauncherActivityInterface.getTaskDimension(mContext, mDeviceProfile, taskDimension);
-                Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH,
-                        "taskbarHeight: " + mDeviceProfile.taskbarHeight);
-                Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH, "taskDimension: " + taskDimension);
-                Rect taskSize = new Rect();
-                LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
-                        taskSize, RecentsPagedOrientationHandler.PORTRAIT);
-                Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH, "calculateTaskSize: " + taskSize);
                 return getUIProperty(Bundle::putParcelable,
-                        recentsViewContainer -> {
-                            Rect lastComputedTaskSize =
-                                    recentsViewContainer.<RecentsView<?, ?>>getOverviewPanel()
-                                            .getLastComputedTaskSize();
-                            Log.d(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH,
-                                    "lastComputedTaskSize: " + lastComputedTaskSize);
-                            return lastComputedTaskSize;
-                        },
+                        recentsViewContainer ->
+                                recentsViewContainer.<RecentsView<?, ?>>getOverviewPanel()
+                                        .getLastComputedTaskSize(),
                         this::getRecentsViewContainer);
             }
 
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e66da52..05bef35 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,7 +20,7 @@
 
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
+import static com.android.wm.shell.shared.GroupedRecentTaskInfo.TYPE_FREEFORM;
 
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
@@ -40,8 +40,8 @@
 import com.android.quickstep.util.GroupTask;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 32e2389..7b9b560 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -54,17 +54,14 @@
 
     private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
     private final SystemUiProxy mSystemUiProxy;
-    private final boolean mAllowMinimizeSplitScreen;
 
     // TODO(141886704): Remove these references when they are no longer needed
     private RecentsAnimationController mController;
 
     private boolean mCancelled;
 
-    public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
-            boolean allowMinimizeSplitScreen) {
+    public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy) {
         mSystemUiProxy = systemUiProxy;
-        mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
     }
 
     @UiThread
@@ -122,7 +119,7 @@
         }
 
         mController = new RecentsAnimationController(animationController,
-                mAllowMinimizeSplitScreen, this::onAnimationFinished);
+                this::onAnimationFinished);
         if (mCancelled) {
             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
                     mController::finishAnimationToApp);
@@ -219,7 +216,6 @@
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "RecentsAnimationCallbacks:");
 
-        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
         pw.println(prefix + "\tmCancelled=" + mCancelled);
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 1b05e28..adcf4ef 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,7 +17,6 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
 
 import android.content.Context;
@@ -52,21 +51,17 @@
     private static final String TAG = "RecentsAnimationController";
     private final RecentsAnimationControllerCompat mController;
     private final Consumer<RecentsAnimationController> mOnFinishedListener;
-    private final boolean mAllowMinimizeSplitScreen;
 
     private boolean mUseLauncherSysBarFlags = false;
-    private boolean mSplitScreenMinimized = false;
     private boolean mFinishRequested = false;
     // Only valid when mFinishRequested == true.
     private boolean mFinishTargetIsLauncher;
     private RunnableList mPendingFinishCallbacks = new RunnableList();
 
     public RecentsAnimationController(RecentsAnimationControllerCompat controller,
-            boolean allowMinimizeSplitScreen,
             Consumer<RecentsAnimationController> onFinishedListener) {
         mController = controller;
         mOnFinishedListener = onFinishedListener;
-        mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
     }
 
     /**
@@ -85,34 +80,17 @@
         if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
             mUseLauncherSysBarFlags = useLauncherSysBarFlags;
             UI_HELPER_EXECUTOR.execute(() -> {
-                if (!ENABLE_SHELL_TRANSITIONS) {
-                    mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
-                } else {
-                    try {
-                        WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
-                                useLauncherSysBarFlags);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to reach window manager", e);
-                    }
+                try {
+                    WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+                            useLauncherSysBarFlags);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to reach window manager", e);
                 }
             });
         }
     }
 
     /**
-     * Indicates that the gesture has crossed the window boundary threshold and we should minimize
-     * if we are in splitscreen.
-     */
-    public void setSplitScreenMinimized(Context context, boolean splitScreenMinimized) {
-        if (!mAllowMinimizeSplitScreen) {
-            return;
-        }
-        if (mSplitScreenMinimized != splitScreenMinimized) {
-            mSplitScreenMinimized = splitScreenMinimized;
-        }
-    }
-
-    /**
      * Remove task remote animation target from
      * {@link RecentsAnimationCallbacks#onTasksAppeared}}.
      */
@@ -272,9 +250,7 @@
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "RecentsAnimationController:");
 
-        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
         pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
-        pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
         pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
         pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f902284..5131774 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -74,6 +74,7 @@
 import com.android.quickstep.util.GestureExclusionManager;
 import com.android.quickstep.util.GestureExclusionManager.ExclusionListener;
 import com.android.quickstep.util.NavBarPosition;
+import com.android.systemui.shared.Flags;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -548,6 +549,13 @@
     }
 
     /**
+     * @return whether the Assistant gesture can be used in 3 button navigation mode.
+     */
+    public boolean supportsAssistantGestureInButtonNav() {
+        return Flags.threeButtonCornerSwipe();
+    }
+
+    /**
      * @param ev An ACTION_DOWN motion event
      * @return whether the given motion event can trigger the assistant over the current task.
      */
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index db03dac..a01ceb2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.recents.data.RecentTasksDataSource;
+import com.android.quickstep.recents.data.TaskVisualsChangeNotifier;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.TaskVisualsChangeListener;
@@ -65,7 +66,8 @@
  */
 @TargetApi(Build.VERSION_CODES.O)
 public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
-        TaskStackChangeListener, TaskVisualsChangeListener, SafeCloseable {
+        TaskStackChangeListener, TaskVisualsChangeListener, TaskVisualsChangeNotifier,
+        SafeCloseable {
 
     // We do not need any synchronization for this variable as its only written on UI thread.
     public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
@@ -287,6 +289,7 @@
     /**
      * Adds a listener for visuals changes
      */
+    @Override
     public void addThumbnailChangeListener(TaskVisualsChangeListener listener) {
         mThumbnailChangeListeners.add(listener);
     }
@@ -294,6 +297,7 @@
     /**
      * Removes a previously added listener
      */
+    @Override
     public void removeThumbnailChangeListener(TaskVisualsChangeListener listener) {
         mThumbnailChangeListeners.remove(listener);
     }
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 3dec381..1be60de 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,7 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
 
 import android.app.WindowConfiguration;
 import android.content.Context;
@@ -33,7 +33,7 @@
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
-import com.android.wm.shell.util.SplitBounds;
+import com.android.wm.shell.shared.split.SplitBounds;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 6f1ab7d..80c07196 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.util.RecentsOrientedState;
+import com.android.systemui.shared.Flags;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -157,7 +158,7 @@
         // Register for navigation mode changes
         mDisplayController.addChangeListener(this);
         DisplayController.Info info = mDisplayController.getInfo();
-        onDisplayInfoChangedInternal(info, CHANGE_ALL, info.getNavigationMode().hasGestures);
+        onDisplayInfoChangedInternal(info, CHANGE_ALL, hasGestures(info.getNavigationMode()));
         runOnDestroy(() -> mDisplayController.removeChangeListener(this));
 
         mOrientationListener = new OrientationEventListener(mContext) {
@@ -229,7 +230,7 @@
      * Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
      */
     public void updateGestureTouchRegions() {
-        if (!mMode.hasGestures) {
+        if (!hasGestures(mMode)) {
             return;
         }
 
@@ -268,7 +269,7 @@
                 | CHANGE_SUPPORTED_BOUNDS)) != 0) {
             mDisplayRotation = info.rotation;
 
-            if (mMode.hasGestures) {
+            if (hasGestures(mMode)) {
                 updateGestureTouchRegions();
                 mOrientationTouchTransformer.createOrAddTouchRegion(info);
                 mCurrentAppRotation = mDisplayRotation;
@@ -295,9 +296,9 @@
             mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
                     mContext.getResources());
 
-            if (forceRegister || (!mMode.hasGestures && newMode.hasGestures)) {
+            if (forceRegister || (!hasGestures(mMode) && hasGestures(newMode))) {
                 setupOrientationSwipeHandler();
-            } else if (mMode.hasGestures && !newMode.hasGestures) {
+            } else if (hasGestures(mMode) && !hasGestures(newMode)) {
                 destroyOrientationSwipeHandlerCallback();
             }
 
@@ -399,7 +400,7 @@
     }
 
     public int getCurrentActiveRotation() {
-        if (!mMode.hasGestures) {
+        if (!hasGestures(mMode)) {
             // touch rotation should always match that of display for 3 button
             return mDisplayRotation;
         }
@@ -416,4 +417,8 @@
     public OrientationTouchTransformer getOrientationTouchTransformer() {
         return mOrientationTouchTransformer;
     }
+
+    private boolean hasGestures(NavigationMode mode) {
+        return mode.hasGestures || (mode == THREE_BUTTONS && Flags.threeButtonCornerSwipe());
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index ead5b7b..dde16c8 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -81,8 +81,6 @@
 import com.android.wm.shell.back.IBackAnimation;
 import com.android.wm.shell.bubbles.IBubbles;
 import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
 import com.android.wm.shell.common.pip.IPip;
 import com.android.wm.shell.common.pip.IPipAnimationListener;
 import com.android.wm.shell.desktopmode.IDesktopMode;
@@ -91,16 +89,19 @@
 import com.android.wm.shell.onehanded.IOneHanded;
 import com.android.wm.shell.recents.IRecentTasks;
 import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
 import com.android.wm.shell.shared.IShellTransitions;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.split.SplitBounds;
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
 import com.android.wm.shell.splitscreen.ISplitScreen;
 import com.android.wm.shell.splitscreen.ISplitScreenListener;
 import com.android.wm.shell.splitscreen.ISplitSelectListener;
 import com.android.wm.shell.startingsurface.IStartingWindow;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -934,6 +935,17 @@
         }
     }
 
+    /** Tells SysUI to show the expanded view. */
+    public void showExpandedView() {
+        try {
+            if (mBubbles != null) {
+                mBubbles.showExpandedView();
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call showExpandedView");
+        }
+    }
+
     //
     // Splitscreen
     //
@@ -1517,7 +1529,7 @@
                 // Aidl bundles need to explicitly set class loader
                 // https://developer.android.com/guide/components/aidl#Bundles
                 if (extras != null) {
-                    extras.setClassLoader(getClass().getClassLoader());
+                    extras.setClassLoader(SplitBounds.class.getClassLoader());
                 }
                 listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps,
                         wallpapers, homeContentInsets, minimizedHomeBounds, extras);
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index ab80a8c..49ec597 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -60,9 +60,8 @@
 import java.util.HashMap;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
-    public static final boolean ENABLE_SHELL_TRANSITIONS = true;
-    public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
-            && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
+    public static final boolean SHELL_TRANSITIONS_ROTATION =
+            SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
 
     private final Context mCtx;
     private RecentsAnimationController mController;
@@ -112,8 +111,9 @@
      */
     public void preloadRecentsAnimation(Intent intent) {
         // Pass null animation handler to indicate this start is for preloading
-        UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
-                .startRecentsActivity(intent, 0, null, null, null));
+        UI_HELPER_EXECUTOR.execute(() -> {
+            ActivityManagerWrapper.getInstance().preloadRecentsActivity(intent);
+        });
     }
 
     boolean shouldIgnoreMotionEvents() {
@@ -159,8 +159,7 @@
 
         final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
         mLastGestureState = gestureState;
-        RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
-                getSystemUiProxy(), containerInterface.allowMinimizeSplitScreen());
+        RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(getSystemUiProxy());
         mCallbacks = newCallbacks;
         mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
             @Override
@@ -190,7 +189,7 @@
                 }
                 mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
 
-                if (ENABLE_SHELL_TRANSITIONS && mTargets.hasRecents
+                if (mTargets.hasRecents
                         // The filtered (MODE_CLOSING) targets only contain 1 home activity.
                         && mTargets.apps.length == 1
                         && mTargets.apps[0].windowConfiguration.getActivityType()
@@ -327,63 +326,43 @@
         mCallbacks.addListener(gestureState);
         mCallbacks.addListener(listener);
 
-        if (ENABLE_SHELL_TRANSITIONS) {
-            final ActivityOptions options = ActivityOptions.makeBasic();
-            options.setPendingIntentBackgroundActivityStartMode(
-                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
-            // Use regular (non-transient) launch for all apps page to control IME.
-            if (!containerInterface.allowAllAppsFromOverview()) {
-                options.setTransientLaunch();
-            }
-            options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+        // Use regular (non-transient) launch for all apps page to control IME.
+        if (!containerInterface.allowAllAppsFromOverview()) {
+            options.setTransientLaunch();
+        }
+        options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
 
-            // Notify taskbar that we should skip reacting to launcher visibility change to
-            // avoid a jumping taskbar.
-            TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
-            if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
-                taskbarUIController.setSkipLauncherVisibilityChange(true);
+        // Notify taskbar that we should skip reacting to launcher visibility change to
+        // avoid a jumping taskbar.
+        TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
+        if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
+            taskbarUIController.setSkipLauncherVisibilityChange(true);
 
-                mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
-                    @Override
-                    public void onRecentsAnimationCanceled(
-                            @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
-                        taskbarUIController.setSkipLauncherVisibilityChange(false);
-                    }
+            mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
+                @Override
+                public void onRecentsAnimationCanceled(
+                        @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
+                    taskbarUIController.setSkipLauncherVisibilityChange(false);
+                }
 
-                    @Override
-                    public void onRecentsAnimationFinished(
-                            @NonNull RecentsAnimationController controller) {
-                        taskbarUIController.setSkipLauncherVisibilityChange(false);
-                    }
-                });
-            }
+                @Override
+                public void onRecentsAnimationFinished(
+                        @NonNull RecentsAnimationController controller) {
+                    taskbarUIController.setSkipLauncherVisibilityChange(false);
+                }
+            });
+        }
 
-            mRecentsAnimationStartPending = getSystemUiProxy()
-                    .startRecentsActivity(intent, options, mCallbacks);
-            if (enableHandleDelayedGestureCallbacks()) {
-                ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
-                        "TaskAnimationManager.startRecentsAnimation(shell transition path): ")
-                        .append("Setting mRecentsAnimationStartPending = ")
-                        .append(mRecentsAnimationStartPending));
-            }
-        } else {
-            UI_HELPER_EXECUTOR.execute(
-                    () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
-                            intent,
-                            eventTime,
-                            mCallbacks,
-                            result -> {
-                                if (enableHandleDelayedGestureCallbacks()) {
-                                    ActiveGestureLog.INSTANCE.addLog(
-                                            new ActiveGestureLog.CompoundString(
-                                                    "TaskAnimationManager.startRecentsAnimation")
-                                                    .append("(legacy path): Setting ")
-                                                    .append("mRecentsAnimationStartPending = ")
-                                                    .append(result));
-                                }
-                                mRecentsAnimationStartPending = result;
-                            },
-                            MAIN_EXECUTOR.getHandler()));
+        mRecentsAnimationStartPending = getSystemUiProxy()
+                .startRecentsActivity(intent, options, mCallbacks);
+        if (enableHandleDelayedGestureCallbacks()) {
+            ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                    "TaskAnimationManager.startRecentsAnimation: ")
+                    .append("Setting mRecentsAnimationStartPending = ")
+                    .append(mRecentsAnimationStartPending));
         }
         gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
         return mCallbacks;
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index dad34ac..785666f 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -315,12 +315,12 @@
             boolean isTaskSplitNotSupported = !task.isDockable ||
                     (intentFlags & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
             boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode;
-            boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
+            boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
             boolean isTaskInExpectedScrollPosition =
                     recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
 
             if (notEnoughTasksToSplit || isTaskSplitNotSupported || hideForExistingMultiWindow
-                    || (isFocusedTask && isTaskInExpectedScrollPosition)) {
+                    || (isLargeTile && isTaskInExpectedScrollPosition)) {
                 return null;
             }
 
@@ -340,11 +340,11 @@
             DeviceProfile deviceProfile = container.getDeviceProfile();
             final TaskView taskView = taskContainer.getTaskView();
             final RecentsView recentsView = taskView.getRecentsView();
-            boolean isLargeTileFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
+            boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
             boolean isInExpectedScrollPosition =
                     recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
             boolean shouldShowActionsButtonInstead =
-                    isLargeTileFocusedTask && isInExpectedScrollPosition;
+                    isLargeTile && isInExpectedScrollPosition;
 
             // No "save app pair" menu item if:
             // - we are in 3p launcher
@@ -431,7 +431,7 @@
 
         @Override
         public void onClick(View view) {
-            if (mTaskView.launchTaskAnimated() != null) {
+            if (mTaskView.launchAsStaticTile() != null) {
                 SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
                         mTaskView.getFirstTask().key.id);
             }
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 3c6c3e4..580dcc2 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -27,6 +27,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.recents.data.HighResLoadingStateNotifier;
 import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource;
 import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
 import com.android.quickstep.util.TaskKeyCache;
@@ -48,7 +49,7 @@
     private final boolean mEnableTaskSnapshotPreloading;
     private final Context mContext;
 
-    public static class HighResLoadingState {
+    public static class HighResLoadingState implements HighResLoadingStateNotifier {
         private boolean mForceHighResThumbnails;
         private boolean mVisible;
         private boolean mFlingingFast;
@@ -65,11 +66,13 @@
             mForceHighResThumbnails = !supportsLowResThumbnails();
         }
 
-        public void addCallback(HighResLoadingStateChangedCallback callback) {
+        @Override
+        public void addCallback(@NonNull HighResLoadingStateChangedCallback callback) {
             mCallbacks.add(callback);
         }
 
-        public void removeCallback(HighResLoadingStateChangedCallback callback) {
+        @Override
+        public void removeCallback(@NonNull HighResLoadingStateChangedCallback callback) {
             mCallbacks.remove(callback);
         }
 
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 88ab528..4587bdd 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -89,6 +89,7 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.ConstantItem;
 import com.android.launcher3.EncryptionType;
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.config.FeatureFlags;
@@ -97,6 +98,7 @@
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarManager;
 import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -107,8 +109,10 @@
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.ScreenOnTracker;
 import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
 import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
@@ -243,7 +247,7 @@
                     return;
                 }
                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+                tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
             });
         }
 
@@ -253,10 +257,9 @@
             executeForTouchInteractionService(tis -> {
                 if (triggeredFromAltTab) {
                     TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                    tis.mOverviewCommandHelper.addCommand(
-                            OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
+                    tis.mOverviewCommandHelper.addCommand(CommandType.KEYBOARD_INPUT);
                 } else {
-                    tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
+                    tis.mOverviewCommandHelper.addCommand(CommandType.SHOW);
                 }
             });
         }
@@ -267,7 +270,7 @@
             executeForTouchInteractionService(tis -> {
                 if (triggeredFromAltTab && !triggeredFromHomeKey) {
                     // onOverviewShownFromAltTab hides the overview and ends at the target app
-                    tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE);
+                    tis.mOverviewCommandHelper.addCommand(CommandType.HIDE);
                 }
             });
         }
@@ -592,12 +595,12 @@
     private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
         @Override
         public void onNavigateHome() {
-            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+            mOverviewCommandHelper.addCommand(CommandType.HOME);
         }
 
         @Override
         public void onToggleOverview() {
-            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+            mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
         }
     };
 
@@ -672,8 +675,9 @@
     private void initInputMonitor(String reason) {
         disposeEventHandlers("Initializing input monitor due to: " + reason);
 
-        if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get()
-                || mTrackpadsConnected.isEmpty())) {
+        if (mDeviceState.isButtonNavMode()
+                && !mDeviceState.supportsAssistantGestureInButtonNav()
+                && (!ENABLE_TRACKPAD_GESTURE.get() || mTrackpadsConnected.isEmpty())) {
             return;
         }
 
@@ -855,7 +859,9 @@
                             .append("); cancelling gesture."),
                     NAVIGATION_MODE_SWITCHED);
             event.setAction(ACTION_CANCEL);
-        } else if (mDeviceState.isButtonNavMode() && !isTrackpadMotionEvent(event)) {
+        } else if (mDeviceState.isButtonNavMode()
+                && !mDeviceState.supportsAssistantGestureInButtonNav()
+                && !isTrackpadMotionEvent(event)) {
             ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ")
                     .append("Cannot process input event: ")
                     .append("using 3-button nav and event is not a trackpad event"));
@@ -901,11 +907,29 @@
             boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive();
             boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event);
             TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+            BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
+            boolean isOnBubbles = bubbleControllers != null
+                    && BubbleBarInputConsumer.isEventOnBubbles(tac, event);
             if (isInSwipeUpTouchRegion && tac != null) {
                 tac.closeKeyboardQuickSwitchView();
             }
-            if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
-                    || isHoverActionWithoutConsumer) {
+            if (mDeviceState.isButtonNavMode()
+                    && mDeviceState.supportsAssistantGestureInButtonNav()) {
+                reasonString.append("in three button mode which supports Assistant gesture");
+                // Consume gesture event for Assistant (all other gestures should do nothing).
+                if (mDeviceState.canTriggerAssistantAction(event)) {
+                    reasonString.append(" and event can trigger assistant action")
+                            .append(", consuming gesture for assistant action");
+                    mGestureState =
+                            createGestureState(mGestureState, getTrackpadGestureType(event));
+                    mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
+                } else {
+                    reasonString.append(" but event cannot trigger Assistant")
+                            .append(", consuming gesture as no-op");
+                    mUncheckedConsumer = InputConsumer.NO_OP;
+                }
+            } else if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
+                    || isHoverActionWithoutConsumer || isOnBubbles) {
                 reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion
                                 ? "one handed mode is not active and event is in swipe up region"
                                 : "isHoverActionWithoutConsumer == true")
@@ -926,8 +950,7 @@
                                 : "event is a trackpad multi-finger swipe")
                         .append(" and event can trigger assistant action")
                         .append(", consuming gesture for assistant action");
-                mGestureState = createGestureState(mGestureState,
-                        getTrackpadGestureType(event));
+                mGestureState = createGestureState(mGestureState, getTrackpadGestureType(event));
                 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
                 // should not interrupt it. QuickSwitch assumes that interruption can only
                 // happen if the next gesture is also quick switch.
@@ -1085,6 +1108,15 @@
 
     private InputConsumer newConsumer(
             GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
+        TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+        BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
+        if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
+            InputConsumer consumer = new BubbleBarInputConsumer(this, bubbleControllers,
+                    mInputMonitorCompat);
+            logInputConsumerSelectionReason(consumer, newCompoundString(
+                    "event is on bubbles, creating new input consumer"));
+            return consumer;
+        }
         AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
         if (progressProxy != null) {
             InputConsumer consumer = new ProgressDelegateInputConsumer(
@@ -1149,7 +1181,6 @@
             }
 
             // If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
-            TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
             if (tac != null && !(base instanceof AssistantInputConsumer)) {
                 // Present always on large screen or on small screen w/ flag
                 boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent
@@ -1180,7 +1211,8 @@
             NavHandle navHandle = tac != null ? tac.getNavHandle()
                     : SystemUiProxy.INSTANCE.get(this);
             if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
-                    && navHandle.canNavHandleBeLongPressed()) {
+                    && navHandle.canNavHandleBeLongPressed()
+                    && !ignoreThreeFingerTrackpadForNavHandleLongPress(mGestureState)) {
                 reasonString.append(NEWLINE_PREFIX)
                         .append(reasonPrefix)
                         .append(SUBSTRING_PREFIX)
@@ -1276,6 +1308,11 @@
         return new CompoundString(NEWLINE_PREFIX).append(substring);
     }
 
+    private boolean ignoreThreeFingerTrackpadForNavHandleLongPress(GestureState gestureState) {
+        return Flags.ignoreThreeFingerTrackpadForNavHandleLongPress()
+                && gestureState.isThreeFingerTrackpadGesture();
+    }
+
     private void logInputConsumerSelectionReason(
             InputConsumer consumer, CompoundString reasonString) {
         ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
new file mode 100644
index 0000000..92031c5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2024 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.inputconsumers;
+
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleDragController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.quickstep.InputConsumer;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Listens for touch events on the bubble bar.
+ */
+public class BubbleBarInputConsumer implements InputConsumer {
+
+    private final BubbleStashController mBubbleStashController;
+    private final BubbleBarViewController mBubbleBarViewController;
+    private final BubbleDragController mBubbleDragController;
+    private final InputMonitorCompat mInputMonitorCompat;
+
+    private boolean mSwipeUpOnBubbleHandle;
+    private boolean mPassedTouchSlop;
+    private boolean mStashedOrCollapsedOnDown;
+
+    private final int mTouchSlop;
+    private final PointF mDownPos = new PointF();
+    private final PointF mLastPos = new PointF();
+    private final long mTimeForTap;
+    private int mActivePointerId = INVALID_POINTER_ID;
+
+    public BubbleBarInputConsumer(Context context, BubbleControllers bubbleControllers,
+            InputMonitorCompat inputMonitorCompat) {
+        mBubbleStashController = bubbleControllers.bubbleStashController;
+        mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
+        mBubbleDragController = bubbleControllers.bubbleDragController;
+        mInputMonitorCompat = inputMonitorCompat;
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mTimeForTap = ViewConfiguration.getTapTimeout();
+    }
+
+    @Override
+    public int getType() {
+        return TYPE_BUBBLE_BAR;
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mActivePointerId = ev.getPointerId(0);
+                mDownPos.set(ev.getX(), ev.getY());
+                mLastPos.set(mDownPos);
+                mStashedOrCollapsedOnDown = mBubbleStashController.isStashed() || isCollapsed();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                if (pointerIndex == INVALID_POINTER_ID) {
+                    break;
+                }
+                mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+
+                float dX = mLastPos.x - mDownPos.x;
+                float dY = mLastPos.y - mDownPos.y;
+                if (!mPassedTouchSlop) {
+                    mPassedTouchSlop = Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
+                }
+                if (mStashedOrCollapsedOnDown && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
+                    boolean verticalGesture = Math.abs(dY) > Math.abs(dX);
+                    if (verticalGesture && !mBubbleDragController.isDragging()) {
+                        mSwipeUpOnBubbleHandle = true;
+                        mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+                        // Bubbles is handling the swipe so make sure no one else gets it.
+                        TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+                        mInputMonitorCompat.pilferPointers();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForTap;
+                if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop
+                        && mStashedOrCollapsedOnDown) {
+                    // Taps on the handle / collapsed state should open the bar
+                    mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+                }
+                break;
+        }
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            cleanupAfterMotionEvent();
+        }
+    }
+
+    private void cleanupAfterMotionEvent() {
+        mPassedTouchSlop = false;
+        mSwipeUpOnBubbleHandle = false;
+    }
+
+    private boolean isCollapsed() {
+        return mBubbleStashController.isBubbleBarVisible()
+                && !mBubbleBarViewController.isExpanded();
+    }
+
+    /**
+     * Returns whether the event is occurring on a visible bubble bar or the bar handle.
+     */
+    public static boolean isEventOnBubbles(TaskbarActivityContext tac, MotionEvent ev) {
+        if (tac == null || !tac.isBubbleBarEnabled()) {
+            return false;
+        }
+        BubbleControllers controllers = tac.getBubbleControllers();
+        if (controllers == null || !controllers.bubbleBarViewController.hasBubbles()) {
+            return false;
+        }
+        if (controllers.bubbleStashController.isStashed()
+                && controllers.bubbleStashedHandleViewController.isPresent()) {
+            return controllers.bubbleStashedHandleViewController.get().isEventOverHandle(ev);
+        } else if (controllers.bubbleBarViewController.isBubbleBarVisible()) {
+            return controllers.bubbleBarViewController.isEventOverBubbleBar(ev);
+        }
+        return false;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index f264364..b66d4cb 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -24,7 +24,6 @@
 import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 
 import android.animation.Animator;
@@ -58,7 +57,6 @@
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.util.TransformParams.BuilderProxy;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 import java.util.HashMap;
@@ -213,15 +211,13 @@
                         // This will come back and cancel the interaction.
                         startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
                         mHomeLaunched = true;
-                    } else if (ENABLE_SHELL_TRANSITIONS) {
-                        if (mTaskAnimationManager.getCurrentCallbacks() != null) {
-                            if (mRecentsAnimationController != null) {
-                                finishRecentsAnimationForShell(dismissTask);
-                            } else {
-                                // the transition of recents animation hasn't started, wait for it
-                                mCancelWhenRecentsStart = true;
-                                mDismissTask = dismissTask;
-                            }
+                    } else if (mTaskAnimationManager.getCurrentCallbacks() != null) {
+                        if (mRecentsAnimationController != null) {
+                            finishRecentsAnimationForShell(dismissTask);
+                        } else {
+                            // the transition of recents animation hasn't started, wait for it
+                            mCancelWhenRecentsStart = true;
+                            mDismissTask = dismissTask;
                         }
                     }
                     mStateCallback.setState(STATE_HANDLER_INVALIDATED);
@@ -278,9 +274,7 @@
     }
 
     private void endRemoteAnimation() {
-        if (mHomeLaunched) {
-            ActivityManagerWrapper.getInstance().cancelRecentsAnimation(false);
-        } else if (mRecentsAnimationController != null) {
+        if (!mHomeLaunched && mRecentsAnimationController != null) {
             mRecentsAnimationController.finishController(
                     false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */);
         }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 9a99d4a..9284e13 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -15,9 +15,7 @@
  */
 package com.android.quickstep.inputconsumers;
 
-import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 
 import static com.android.launcher3.Flags.enableCursorHoverStates;
@@ -43,12 +41,12 @@
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarThresholdUtils;
 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
-import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.touch.OverScroll;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
@@ -69,9 +67,6 @@
     private final int mTaskbarNavThresholdY;
     private final boolean mIsTaskbarAllAppsOpen;
     private boolean mHasPassedTaskbarNavThreshold;
-    private boolean mIsInBubbleBarArea;
-    private boolean mIsVerticalGestureOverBubbleBar;
-    private boolean mIsPassedBubbleBarSlop;
     private final int mTouchSlop;
 
     private final PointF mDownPos = new PointF();
@@ -159,9 +154,6 @@
                         if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) {
                             mTransitionCallback.onActionDown();
                         }
-                        if (mIsTransientTaskbar && isInBubbleBarArea(x)) {
-                            mIsInBubbleBarArea = true;
-                        }
                         break;
                     case MotionEvent.ACTION_POINTER_UP:
                         int ptrIdx = ev.getActionIndex();
@@ -185,18 +177,6 @@
                         float dX = mLastPos.x - mDownPos.x;
                         float dY = mLastPos.y - mDownPos.y;
 
-                        if (!mIsPassedBubbleBarSlop && mIsInBubbleBarArea) {
-                            boolean passedSlop =
-                                    Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
-                            if (passedSlop) {
-                                mIsPassedBubbleBarSlop = true;
-                                mIsVerticalGestureOverBubbleBar = Math.abs(dY) > Math.abs(dX);
-                                if (mIsVerticalGestureOverBubbleBar) {
-                                    setActive(ev);
-                                }
-                            }
-                        }
-
                         if (mIsTransientTaskbar) {
                             boolean passedTaskbarNavThreshold = dY < 0
                                     && Math.abs(dY) >= mTaskbarNavThreshold;
@@ -204,11 +184,7 @@
                             if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold
                                     && !mGestureState.isInExtendedSlopRegion()) {
                                 mHasPassedTaskbarNavThreshold = true;
-                                if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) {
-                                    mTaskbarActivityContext.onSwipeToOpenBubblebar();
-                                } else {
-                                    mTaskbarActivityContext.onSwipeToUnstashTaskbar();
-                                }
+                                mTaskbarActivityContext.onSwipeToUnstashTaskbar();
                             }
 
                             if (dY < 0) {
@@ -225,46 +201,13 @@
                         break;
                     case MotionEvent.ACTION_BUTTON_RELEASE:
                         if (isStashedTaskbarHovered) {
-                            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+                            mOverviewCommandHelper.addCommand(CommandType.HOME);
                         }
                         break;
                 }
             }
-            boolean isMovingInBubbleBarArea = mIsInBubbleBarArea && ev.getAction() == ACTION_MOVE;
             if (!isStashedTaskbarHovered) {
-                // if we're moving in the bubble bar area but we haven't passed the slop yet, don't
-                // propagate to the delegate, until we can determine the direction of the gesture.
-                if (!isMovingInBubbleBarArea || mIsPassedBubbleBarSlop) {
-                    mDelegate.onMotionEvent(ev);
-                }
-            }
-        } else if (mIsVerticalGestureOverBubbleBar) {
-            // if we get here then this gesture is a vertical swipe over the bubble bar.
-            // we're also active and there's no need to delegate any additional motion events. the
-            // rest of the gesture will be handled here.
-            switch (ev.getAction()) {
-                case ACTION_MOVE:
-                    int pointerIndex = ev.findPointerIndex(mActivePointerId);
-                    if (pointerIndex == INVALID_POINTER_ID) {
-                        break;
-                    }
-                    mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
-
-                    float dY = mLastPos.y - mDownPos.y;
-
-                    // bubble bar swipe gesture uses the same threshold as the taskbar.
-                    boolean passedTaskbarNavThreshold = dY < 0
-                            && Math.abs(dY) >= mTaskbarNavThreshold;
-
-                    if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
-                        mHasPassedTaskbarNavThreshold = true;
-                        mTaskbarActivityContext.onSwipeToOpenBubblebar();
-                    }
-                    break;
-                case ACTION_UP:
-                case ACTION_CANCEL:
-                    cleanupAfterMotionEvent();
-                    break;
+                mDelegate.onMotionEvent(ev);
             }
         }
     }
@@ -301,9 +244,6 @@
             mTransitionCallback.onActionEnd();
         }
         mHasPassedTaskbarNavThreshold = false;
-        mIsInBubbleBarArea = false;
-        mIsVerticalGestureOverBubbleBar = false;
-        mIsPassedBubbleBarSlop = false;
 
         if (mVelocityTracker != null) {
             mVelocityTracker.recycle();
@@ -313,23 +253,6 @@
         mMotionMoveCount = 0;
     }
 
-    private boolean isInBubbleBarArea(float x) {
-        if (mTaskbarActivityContext == null || !mIsTransientTaskbar) {
-            return false;
-        }
-        BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers();
-        if (controllers == null) {
-            return false;
-        }
-        if (controllers.bubbleStashController.isStashed()
-                && controllers.bubbleStashedHandleViewController.isPresent()) {
-            return controllers.bubbleStashedHandleViewController.get().containsX((int) x);
-        } else {
-            Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds();
-            return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right;
-        }
-    }
-
     /**
      * Listen for hover events for the stashed taskbar.
      *
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 36ea926..acc9959 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.quickstep.TouchInteractionService.TISBinder;
 import com.android.quickstep.interaction.TutorialController.TutorialType;
+import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TISBindHelper;
 
 import java.util.ArrayList;
@@ -54,8 +55,6 @@
     static final String KEY_TUTORIAL_TYPE = "tutorial_type";
     static final String KEY_GESTURE_COMPLETE = "gesture_complete";
     static final String KEY_USE_TUTORIAL_MENU = "use_tutorial_menu";
-    public static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
-    public static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
 
     @Nullable private TutorialType[] mTutorialSteps;
     private GestureSandboxFragment mCurrentFragment;
@@ -170,10 +169,7 @@
                 getApplicationContext()).getDeviceProfile(this);
         if (deviceProfile.isTablet) {
             // The tutorial will work in either orientation if the height and width are similar
-            boolean isAspectRatioSquare =
-                    deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
-                            && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND;
-            boolean showRotationPrompt = !isAspectRatioSquare
+            boolean showRotationPrompt = !LayoutUtils.isAspectRatioSquare(deviceProfile.aspectRatio)
                     && getResources().getConfiguration().orientation
                     == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index ec04cb7..658975c 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -37,6 +37,7 @@
 import androidx.annotation.VisibleForTesting
 import androidx.core.util.component1
 import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.Flags
 import com.android.launcher3.LauncherAnimUtils
@@ -242,7 +243,30 @@
         lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
     }
 
-    override fun getDwbLayoutTranslations(
+    override fun updateDwbBannerLayout(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        isGroupedTaskView: Boolean,
+        deviceProfile: DeviceProfile,
+        snapshotViewWidth: Int,
+        snapshotViewHeight: Int,
+        banner: View
+    ) {
+        banner.pivotX = 0f
+        banner.pivotY = 0f
+        banner.rotation = degreesRotated
+        banner.updateLayoutParams<FrameLayout.LayoutParams> {
+            gravity = Gravity.TOP or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+            width =
+                if (isGroupedTaskView) {
+                    snapshotViewHeight
+                } else {
+                    taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+                }
+        }
+    }
+
+    override fun getDwbBannerTranslations(
         taskViewWidth: Int,
         taskViewHeight: Int,
         splitBounds: SplitBounds?,
@@ -252,39 +276,25 @@
         banner: View
     ): Pair<Float, Float> {
         val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
-        val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
         val translationX = banner.height.toFloat()
-
-        val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
-        bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START
-        banner.pivotX = 0f
-        banner.pivotY = 0f
-        banner.rotation = degreesRotated
-
-        if (splitBounds == null) {
-            // Single, fullscreen case
-            bannerParams.width = taskViewHeight - snapshotParams.topMargin
-            return Pair(translationX, snapshotParams.topMargin.toFloat())
-        }
-
-        // Set correct width and translations
         val translationY: Float
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[0].measuredHeight
+        if (splitBounds == null) {
             translationY = snapshotParams.topMargin.toFloat()
         } else {
-            bannerParams.width = thumbnailViews[1].measuredHeight
-            val topLeftTaskPlusDividerPercent =
-                if (splitBounds.appsStackedVertically) {
-                    splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
-                } else {
-                    splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
-                }
-            translationY =
-                snapshotParams.topMargin +
-                    (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+            if (desiredTaskId == splitBounds.leftTopTaskId) {
+                translationY = snapshotParams.topMargin.toFloat()
+            } else {
+                val topLeftTaskPlusDividerPercent =
+                    if (splitBounds.appsStackedVertically) {
+                        splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
+                    } else {
+                        splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
+                    }
+                translationY =
+                    snapshotParams.topMargin +
+                        (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+            }
         }
-
         return Pair(translationX, translationY)
     }
 
@@ -300,6 +310,7 @@
         if (isRtl) displacement < 0 else displacement > 0
 
     override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1
+
     /* -------------------- */
 
     override fun getChildBounds(
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index eeacee1..cc022b2 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -243,54 +243,54 @@
     }
 
     @Override
-    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
-            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
-            View[] thumbnailViews, int desiredTaskId, View banner) {
-        float translationX = 0;
-        float translationY = 0;
+    public void updateDwbBannerLayout(int taskViewWidth, int taskViewHeight,
+            boolean isGroupedTaskView, @NonNull DeviceProfile deviceProfile,
+            int snapshotViewWidth, int snapshotViewHeight, @NonNull View banner) {
         FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
         banner.setPivotX(0);
         banner.setPivotY(0);
         banner.setRotation(getDegreesRotated());
-        if (splitBounds == null) {
-            // Single, fullscreen case
+        if (isGroupedTaskView) {
+            bannerParams.gravity =
+                    BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
+            bannerParams.width = snapshotViewWidth;
+        } else {
             bannerParams.width = MATCH_PARENT;
             bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL;
-            return new Pair<>(translationX, translationY);
         }
+        banner.setLayoutParams(bannerParams);
+    }
 
-        bannerParams.gravity =
-                BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
-
-        // Set correct width
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[0].getMeasuredWidth();
-        } else {
-            bannerParams.width = thumbnailViews[1].getMeasuredWidth();
-        }
-
-        // Set translations
-        if (deviceProfile.isLeftRightSplit) {
-            if (desiredTaskId == splitBounds.rightBottomTaskId) {
-                float leftTopTaskPercent = splitBounds.appsStackedVertically
-                        ? splitBounds.topTaskPercent
-                        : splitBounds.leftTaskPercent;
-                float dividerThicknessPercent = splitBounds.appsStackedVertically
-                        ? splitBounds.dividerHeightPercent
-                        : splitBounds.dividerWidthPercent;
-                translationX = ((taskViewWidth * leftTopTaskPercent)
-                        + (taskViewWidth * dividerThicknessPercent));
-            }
-        } else {
-            if (desiredTaskId == splitBounds.leftTopTaskId) {
-                FrameLayout.LayoutParams snapshotParams =
-                        (FrameLayout.LayoutParams) thumbnailViews[0]
-                                .getLayoutParams();
-                float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
-                        ? (1f - splitBounds.topTaskPercent)
-                        : (1f - splitBounds.leftTaskPercent);
-                translationY = -((taskViewHeight - snapshotParams.topMargin)
-                        * bottomRightTaskPlusDividerPercent);
+    @NonNull
+    @Override
+    public Pair<Float, Float> getDwbBannerTranslations(int taskViewWidth,
+            int taskViewHeight, SplitBounds splitBounds, @NonNull DeviceProfile deviceProfile,
+            @NonNull View[] thumbnailViews, int desiredTaskId, @NonNull View banner) {
+        float translationX = 0;
+        float translationY = 0;
+        if (splitBounds != null) {
+            if (deviceProfile.isLeftRightSplit) {
+                if (desiredTaskId == splitBounds.rightBottomTaskId) {
+                    float leftTopTaskPercent = splitBounds.appsStackedVertically
+                            ? splitBounds.topTaskPercent
+                            : splitBounds.leftTaskPercent;
+                    float dividerThicknessPercent = splitBounds.appsStackedVertically
+                            ? splitBounds.dividerHeightPercent
+                            : splitBounds.dividerWidthPercent;
+                    translationX = ((taskViewWidth * leftTopTaskPercent)
+                            + (taskViewWidth * dividerThicknessPercent));
+                }
+            } else {
+                if (desiredTaskId == splitBounds.leftTopTaskId) {
+                    FrameLayout.LayoutParams snapshotParams =
+                            (FrameLayout.LayoutParams) thumbnailViews[0]
+                                    .getLayoutParams();
+                    float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
+                            ? (1f - splitBounds.topTaskPercent)
+                            : (1f - splitBounds.leftTaskPercent);
+                    translationY = -((taskViewHeight - snapshotParams.topMargin)
+                            * bottomRightTaskPlusDividerPercent);
+                }
             }
         }
         return new Pair<>(translationX, translationY);
@@ -535,6 +535,18 @@
             int parentWidth, int parentHeight, SplitBounds splitBoundsConfig,
             DeviceProfile dp, boolean isRtl) {
         int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
+
+        FrameLayout.LayoutParams primaryParams =
+                (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
+        FrameLayout.LayoutParams secondaryParams =
+                (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
+
+        // Reset margin and translations that aren't used in this method, but are used in other
+        // `RecentsPagedOrientationHandler` variants.
+        secondaryParams.topMargin = 0;
+        primaryParams.topMargin = spaceAboveSnapshot;
+        primarySnapshot.setTranslationY(0);
+
         int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
         float dividerScale = splitBoundsConfig.appsStackedVertically
                 ? splitBoundsConfig.dividerHeightPercent
@@ -552,24 +564,14 @@
                 secondarySnapshot.setTranslationX(translationX);
                 primarySnapshot.setTranslationX(0);
             }
-            secondarySnapshot.setTranslationY(spaceAboveSnapshot);
 
-            // Reset unused translations
-            primarySnapshot.setTranslationY(0);
+            secondarySnapshot.setTranslationY(spaceAboveSnapshot);
         } else {
             float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
             float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
             secondarySnapshot.setTranslationY(translationY);
 
-            FrameLayout.LayoutParams primaryParams =
-                    (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
-            FrameLayout.LayoutParams secondaryParams =
-                    (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
-            secondaryParams.topMargin = 0;
-            primaryParams.topMargin = spaceAboveSnapshot;
-
-            // Reset unused translations
-            primarySnapshot.setTranslationY(0);
+            // Reset unused translations.
             secondarySnapshot.setTranslationX(0);
             primarySnapshot.setTranslationX(0);
         }
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index df4b030..06a0685 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -199,6 +199,7 @@
         parentWidth: Int,
         parentHeight: Int
     ): Pair<Point, Point>
+
     // Overview TaskMenuView methods
     /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
     fun setTaskIconParams(
@@ -294,13 +295,24 @@
         deviceProfile: DeviceProfile
     )
 
+    /** Layout a Digital Wellbeing Banner on its parent. TaskView. */
+    fun updateDwbBannerLayout(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        isGroupedTaskView: Boolean,
+        deviceProfile: DeviceProfile,
+        snapshotViewWidth: Int,
+        snapshotViewHeight: Int,
+        banner: View
+    )
+
     /**
-     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+     * Calculates the translations where a Digital Wellbeing Banner should be apply on its parent
      * TaskView.
      *
      * @return A Pair of Floats representing the proper x and y translations.
      */
-    fun getDwbLayoutTranslations(
+    fun getDwbBannerTranslations(
         taskViewWidth: Int,
         taskViewHeight: Int,
         splitBounds: SplitConfigurationOptions.SplitBounds?,
@@ -309,6 +321,7 @@
         desiredTaskId: Int,
         banner: View
     ): Pair<Float, Float>
+
     // The following are only used by TaskViewTouchHandler.
 
     /** @return Either VERTICAL or HORIZONTAL. */
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index 333359f..a972e8c 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -28,6 +28,7 @@
 import android.widget.FrameLayout
 import androidx.core.util.component1
 import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.Flags
 import com.android.launcher3.R
@@ -125,7 +126,30 @@
         }
     }
 
-    override fun getDwbLayoutTranslations(
+    override fun updateDwbBannerLayout(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        isGroupedTaskView: Boolean,
+        deviceProfile: DeviceProfile,
+        snapshotViewWidth: Int,
+        snapshotViewHeight: Int,
+        banner: View
+    ) {
+        banner.pivotX = 0f
+        banner.pivotY = 0f
+        banner.rotation = degreesRotated
+        banner.updateLayoutParams<FrameLayout.LayoutParams> {
+            gravity = Gravity.BOTTOM or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+            width =
+                if (isGroupedTaskView) {
+                    snapshotViewHeight
+                } else {
+                    taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+                }
+        }
+    }
+
+    override fun getDwbBannerTranslations(
         taskViewWidth: Int,
         taskViewHeight: Int,
         splitBounds: SplitBounds?,
@@ -135,39 +159,26 @@
         banner: View
     ): Pair<Float, Float> {
         val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
-        val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
-
-        val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
-        bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START
-        banner.pivotX = 0f
-        banner.pivotY = 0f
-        banner.rotation = degreesRotated
-
         val translationX: Float = (taskViewWidth - banner.height).toFloat()
-        if (splitBounds == null) {
-            // Single, fullscreen case
-            bannerParams.width = taskViewHeight - snapshotParams.topMargin
-            return Pair(translationX, banner.height.toFloat())
-        }
-
-        // Set correct width and translations
         val translationY: Float
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[0].measuredHeight
-            val bottomRightTaskPlusDividerPercent =
-                if (splitBounds.appsStackedVertically) {
-                    1f - splitBounds.topTaskPercent
-                } else {
-                    1f - splitBounds.leftTaskPercent
-                }
-            translationY =
-                banner.height -
-                    (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent
-        } else {
-            bannerParams.width = thumbnailViews[1].measuredHeight
+        if (splitBounds == null) {
             translationY = banner.height.toFloat()
+        } else {
+            if (desiredTaskId == splitBounds.leftTopTaskId) {
+                val bottomRightTaskPlusDividerPercent =
+                    if (splitBounds.appsStackedVertically) {
+                        1f - splitBounds.topTaskPercent
+                    } else {
+                        1f - splitBounds.leftTaskPercent
+                    }
+                translationY =
+                    banner.height -
+                        (taskViewHeight - snapshotParams.topMargin) *
+                            bottomRightTaskPlusDividerPercent
+            } else {
+                translationY = banner.height.toFloat()
+            }
         }
-
         return Pair(translationX, translationY)
     }
 
@@ -339,6 +350,7 @@
         if (isRtl) displacement > 0 else displacement < 0
 
     override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1
+
     /* -------------------- */
 
     override fun getSplitIconsPosition(
diff --git a/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..df546ca
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+/** Notifies added callbacks that high res state has changed */
+interface HighResLoadingStateNotifier {
+    /** Adds a callback for high res loading state */
+    fun addCallback(callback: HighResLoadingStateChangedCallback)
+
+    /** Removes a callback for high res loading state */
+    fun removeCallback(callback: HighResLoadingStateChangedCallback)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index 4f7a541..9c4248c 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -41,10 +41,4 @@
      * populated e.g. icons/thumbnails etc.
      */
     fun setVisibleTasks(visibleTaskIdList: List<Int>)
-
-    /**
-     * Override [ThumbnailData] with a map of taskId to [ThumbnailData]. The override only applies
-     * if the tasks are already visible, and will be invalidated when tasks become invisible.
-     */
-    fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
 }
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
index feed2fd..d2cb595 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
@@ -23,6 +23,4 @@
  */
 data class RecentsDeviceProfile(
     val isLargeScreen: Boolean,
-    val widthPx: Int,
-    val heightPx: Int,
 )
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
index ce39ff1..c64453d 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
@@ -26,7 +26,5 @@
     RecentsDeviceProfileRepository {
 
     override fun getRecentsDeviceProfile() =
-        with(container.deviceProfile) {
-            RecentsDeviceProfile(isLargeScreen = isTablet, widthPx = widthPx, heightPx = heightPx)
-        }
+        with(container.deviceProfile) { RecentsDeviceProfile(isLargeScreen = isTablet) }
 }
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..6e7789d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+/** Notifies added listeners that task visuals have changed */
+interface TaskVisualsChangeNotifier {
+    /** Adds a listener for visuals changes */
+    fun addThumbnailChangeListener(listener: TaskVisualsChangeListener)
+
+    /** Removes a listener for visuals changes */
+    fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
new file mode 100644
index 0000000..a141e89
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import android.os.UserHandle
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.quickstep.util.TaskVisualsChangeListener
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/** Delegates the checking of task visuals (thumbnails, high res changes, icons) */
+interface TaskVisualsChangedDelegate :
+    TaskVisualsChangeListener, HighResLoadingStateChangedCallback {
+    /** Registers a callback for visuals relating to icons */
+    fun registerTaskIconChangedCallback(
+        taskKey: Task.TaskKey,
+        taskIconChangedCallback: TaskIconChangedCallback
+    )
+
+    /** Unregisters a callback for visuals relating to icons */
+    fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey)
+
+    /** Registers a callback for visuals relating to thumbnails */
+    fun registerTaskThumbnailChangedCallback(
+        taskKey: Task.TaskKey,
+        taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+    )
+
+    /** Unregisters a callback for visuals relating to thumbnails */
+    fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey)
+
+    /** A callback for task icon changes */
+    interface TaskIconChangedCallback {
+        /** Informs the listener that the task icon has changed */
+        fun onTaskIconChanged()
+    }
+
+    /** A callback for task thumbnail changes */
+    interface TaskThumbnailChangedCallback {
+        /** Informs the listener that the task thumbnail data has changed to [thumbnailData] */
+        fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?)
+
+        /** Informs the listener that the default resolution for loading thumbnails has changed */
+        fun onHighResLoadingStateChanged()
+    }
+}
+
+class TaskVisualsChangedDelegateImpl(
+    private val taskVisualsChangeNotifier: TaskVisualsChangeNotifier,
+    private val highResLoadingStateNotifier: HighResLoadingStateNotifier,
+) : TaskVisualsChangedDelegate {
+    private val taskIconChangedCallbacks =
+        mutableMapOf<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>()
+    private val taskThumbnailChangedCallbacks =
+        mutableMapOf<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>()
+    private var isListening = false
+
+    @Synchronized
+    private fun onCallbackRegistered() {
+        if (isListening) return
+
+        taskVisualsChangeNotifier.addThumbnailChangeListener(this)
+        highResLoadingStateNotifier.addCallback(this)
+        isListening = true
+    }
+
+    @Synchronized
+    private fun onCallbackUnregistered() {
+        if (!isListening) return
+
+        if (taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size == 0) {
+            taskVisualsChangeNotifier.removeThumbnailChangeListener(this)
+            highResLoadingStateNotifier.removeCallback(this)
+        }
+
+        isListening = false
+    }
+
+    override fun onTaskIconChanged(taskId: Int) {
+        taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() }
+    }
+
+    override fun onTaskIconChanged(pkg: String, user: UserHandle) {
+        taskIconChangedCallbacks.values
+            .filter { (taskKey, _) ->
+                pkg == taskKey.packageName && user.identifier == taskKey.userId
+            }
+            .forEach { (_, callback) -> callback.onTaskIconChanged() }
+    }
+
+    override fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData?): Task? {
+        taskThumbnailChangedCallbacks[taskId]?.let { (_, callback) ->
+            callback.onTaskThumbnailChanged(thumbnailData)
+        }
+        return null
+    }
+
+    override fun onHighResLoadingStateChanged(enabled: Boolean) {
+        taskThumbnailChangedCallbacks.values.forEach { (_, callback) ->
+            callback.onHighResLoadingStateChanged()
+        }
+    }
+
+    override fun registerTaskIconChangedCallback(
+        taskKey: Task.TaskKey,
+        taskIconChangedCallback: TaskIconChangedCallback
+    ) {
+        taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
+        onCallbackRegistered()
+    }
+
+    override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) {
+        taskIconChangedCallbacks.remove(taskKey.id)
+        onCallbackUnregistered()
+    }
+
+    override fun registerTaskThumbnailChangedCallback(
+        taskKey: Task.TaskKey,
+        taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+    ) {
+        taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
+        onCallbackRegistered()
+    }
+
+    override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) {
+        taskThumbnailChangedCallbacks.remove(taskKey.id)
+        onCallbackUnregistered()
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 6f9d157..eb3c2d1 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -18,6 +18,8 @@
 
 import android.graphics.drawable.Drawable
 import com.android.launcher3.util.coroutines.DispatcherProvider
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
 import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
 import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
 import com.android.quickstep.util.GroupTask
@@ -26,18 +28,20 @@
 import kotlin.coroutines.resume
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.distinctUntilChangedBy
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 
@@ -46,12 +50,12 @@
     private val recentsModel: RecentTasksDataSource,
     private val taskThumbnailDataSource: TaskThumbnailDataSource,
     private val taskIconDataSource: TaskIconDataSource,
+    private val taskVisualsChangedDelegate: TaskVisualsChangedDelegate,
     recentsCoroutineScope: CoroutineScope,
     private val dispatcherProvider: DispatcherProvider,
 ) : RecentTasksRepository {
     private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
     private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
-    private val thumbnailOverride = MutableStateFlow(mapOf<Int, ThumbnailData>())
 
     private val taskData =
         groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
@@ -85,15 +89,13 @@
             .distinctUntilChanged()
 
     private val augmentedTaskData: Flow<List<Task>> =
-        combine(taskData, thumbnailQueryResults, iconQueryResults, thumbnailOverride) {
+        combine(taskData, thumbnailQueryResults, iconQueryResults) {
                 tasks,
                 thumbnailQueryResults,
-                iconQueryResults,
-                thumbnailOverride ->
+                iconQueryResults ->
                 tasks.onEach { task ->
                     // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
-                    task.thumbnail =
-                        thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
+                    task.thumbnail = thumbnailQueryResults[task.key.id]
 
                     // TODO(b/352331675) don't load icons for DesktopTaskView
                     // Add retrieved icons + remove unnecessary icons
@@ -121,61 +123,76 @@
 
     override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
         this.visibleTaskIds.value = visibleTaskIdList.toSet()
-        addOrUpdateThumbnailOverride(emptyMap())
-    }
-
-    override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
-        this.thumbnailOverride.value =
-            this.thumbnailOverride.value
-                .toMutableMap()
-                .apply { putAll(thumbnailOverride) }
-                .filterKeys(this.visibleTaskIds.value::contains)
     }
 
     /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
-    private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = flow {
-        emit(task.key.id to task.thumbnail)
-        val thumbnailDataResult: ThumbnailData? =
-            withContext(dispatcherProvider.main) {
-                suspendCancellableCoroutine { continuation ->
-                    val cancellableTask =
-                        taskThumbnailDataSource.getThumbnailInBackground(task) {
-                            continuation.resume(it)
-                        }
-                    continuation.invokeOnCancellation { cancellableTask?.cancel() }
+    private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = callbackFlow {
+        trySend(task.key.id to task.thumbnail)
+        trySend(task.key.id to getThumbnailFromDataSource(task))
+
+        val callback =
+            object : TaskThumbnailChangedCallback {
+                override fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?) {
+                    trySend(task.key.id to thumbnailData)
+                }
+
+                override fun onHighResLoadingStateChanged() {
+                    launch { trySend(task.key.id to getThumbnailFromDataSource(task)) }
                 }
             }
-        emit(task.key.id to thumbnailDataResult)
+        taskVisualsChangedDelegate.registerTaskThumbnailChangedCallback(task.key, callback)
+        awaitClose { taskVisualsChangedDelegate.unregisterTaskThumbnailChangedCallback(task.key) }
     }
 
-    /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
+    /** Flow wrapper for [TaskIconDataSource.getIconInBackground] api */
     private fun getIconDataRequest(task: Task): IconDataRequest =
-        flow {
-                emit(task.key.id to task.getTaskIconQueryResponse())
-                val iconDataResponse: TaskIconQueryResponse? =
-                    withContext(dispatcherProvider.main) {
-                        suspendCancellableCoroutine { continuation ->
-                            val cancellableTask =
-                                taskIconDataSource.getIconInBackground(task) {
-                                    icon,
-                                    contentDescription,
-                                    title ->
-                                    icon.constantState?.let {
-                                        continuation.resume(
-                                            TaskIconQueryResponse(
-                                                it.newDrawable().mutate(),
-                                                contentDescription,
-                                                title
-                                            )
-                                        )
-                                    }
-                                }
-                            continuation.invokeOnCancellation { cancellableTask?.cancel() }
+        callbackFlow {
+                trySend(task.key.id to task.getTaskIconQueryResponse())
+                trySend(task.key.id to getIconFromDataSource(task))
+
+                val callback =
+                    object : TaskIconChangedCallback {
+                        override fun onTaskIconChanged() {
+                            launch { trySend(task.key.id to getIconFromDataSource(task)) }
                         }
                     }
-                emit(task.key.id to iconDataResponse)
+                taskVisualsChangedDelegate.registerTaskIconChangedCallback(task.key, callback)
+                awaitClose {
+                    taskVisualsChangedDelegate.unregisterTaskIconChangedCallback(task.key)
+                }
             }
             .distinctUntilChanged()
+
+    private suspend fun getThumbnailFromDataSource(task: Task) =
+        withContext(dispatcherProvider.main) {
+            suspendCancellableCoroutine { continuation ->
+                val cancellableTask =
+                    taskThumbnailDataSource.getThumbnailInBackground(task) {
+                        continuation.resume(it)
+                    }
+                continuation.invokeOnCancellation { cancellableTask?.cancel() }
+            }
+        }
+
+    private suspend fun getIconFromDataSource(task: Task) =
+        withContext(dispatcherProvider.main) {
+            suspendCancellableCoroutine { continuation ->
+                val cancellableTask =
+                    taskIconDataSource.getIconInBackground(task) { icon, contentDescription, title
+                        ->
+                        icon.constantState?.let {
+                            continuation.resume(
+                                TaskIconQueryResponse(
+                                    it.newDrawable().mutate(),
+                                    contentDescription,
+                                    title
+                                )
+                            )
+                        }
+                    }
+                continuation.invokeOnCancellation { cancellableTask?.cancel() }
+            }
+        }
 }
 
 data class TaskIconQueryResponse(
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index d8156b1..0a5544f 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -22,12 +22,13 @@
 import com.android.launcher3.util.coroutines.ProductionDispatchers
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.recents.data.RecentTasksRepository
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegateImpl
 import com.android.quickstep.recents.data.TasksRepository
 import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
 import com.android.quickstep.recents.usecase.GetThumbnailUseCase
 import com.android.quickstep.recents.usecase.SysUiStatusNavFlagsUseCase
 import com.android.quickstep.recents.viewmodel.RecentsViewData
-import com.android.quickstep.task.thumbnail.GetSplashSizeUseCase
 import com.android.quickstep.task.thumbnail.SplashAlphaUseCase
 import com.android.quickstep.task.thumbnail.TaskThumbnailViewData
 import com.android.quickstep.task.viewmodel.TaskContainerData
@@ -61,14 +62,22 @@
             val recentsCoroutineScope =
                 CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
             set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
+            val recentsModel = RecentsModel.INSTANCE.get(appContext)
+            val taskVisualsChangedDelegate =
+                TaskVisualsChangedDelegateImpl(
+                    recentsModel,
+                    recentsModel.thumbnailCache.highResLoadingState
+                )
+            set(TaskVisualsChangedDelegate::class.java.simpleName, taskVisualsChangedDelegate)
 
             // Create RecentsTaskRepository singleton
             val recentTasksRepository: RecentTasksRepository =
-                with(RecentsModel.INSTANCE.get(appContext)) {
+                with(recentsModel) {
                     TasksRepository(
                         this,
                         thumbnailCache,
                         iconCache,
+                        taskVisualsChangedDelegate,
                         recentsCoroutineScope,
                         ProductionDispatchers
                     )
@@ -156,6 +165,7 @@
                             thumbnailCache,
                             iconCache,
                             get(),
+                            get(),
                             ProductionDispatchers
                         )
                     }
@@ -176,7 +186,6 @@
                         getThumbnailPositionUseCase = inject(),
                         tasksRepository = inject(),
                         splashAlphaUseCase = inject(scopeId),
-                        getSplashSizeUseCase = inject(scopeId),
                     )
                 TaskOverlayViewModel::class.java -> {
                     val task = extras["Task"] as Task
@@ -204,12 +213,6 @@
                         tasksRepository = inject(),
                         rotationStateRepository = inject(),
                     )
-                GetSplashSizeUseCase::class.java ->
-                    GetSplashSizeUseCase(
-                        taskThumbnailViewData = inject(scopeId),
-                        taskViewData = inject(scopeId, extras),
-                        deviceProfileRepository = inject(),
-                    )
                 else -> {
                     log("Factory for ${modelClass.simpleName} not defined!", Log.ERROR)
                     error("Factory for ${modelClass.simpleName} not defined!")
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index b1f46a3..1716f2e 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -58,10 +58,6 @@
         recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
     }
 
-    fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
-        recentsTasksRepository.addOrUpdateThumbnailOverride(thumbnailOverride)
-    }
-
     suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
         combine(
                 updatedThumbnails.map {
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt b/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt
deleted file mode 100644
index 145957a..0000000
--- a/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2024 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.task.thumbnail
-
-import android.graphics.Point
-import android.graphics.drawable.Drawable
-import com.android.quickstep.recents.data.RecentsDeviceProfileRepository
-import com.android.quickstep.task.viewmodel.TaskViewData
-import kotlin.math.min
-
-class GetSplashSizeUseCase(
-    private val taskThumbnailViewData: TaskThumbnailViewData,
-    private val taskViewData: TaskViewData,
-    private val deviceProfileRepository: RecentsDeviceProfileRepository,
-) {
-    fun execute(splashImage: Drawable): Point {
-        val recentsDeviceProfile = deviceProfileRepository.getRecentsDeviceProfile()
-        val screenWidth = recentsDeviceProfile.widthPx
-        val screenHeight = recentsDeviceProfile.heightPx
-        val scaleAtFullscreen =
-            min(
-                screenWidth / taskThumbnailViewData.width.value,
-                screenHeight / taskThumbnailViewData.height.value,
-            )
-        val scaleFactor: Float = 1f / taskViewData.nonGridScale.value / scaleAtFullscreen
-        return Point(
-            (splashImage.intrinsicWidth * scaleFactor / taskThumbnailViewData.scaleX.value).toInt(),
-            (splashImage.intrinsicHeight * scaleFactor / taskThumbnailViewData.scaleY.value)
-                .toInt(),
-        )
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index a6be9f6..36a86f2 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -17,7 +17,6 @@
 package com.android.quickstep.task.thumbnail
 
 import android.graphics.Bitmap
-import android.graphics.Point
 import android.graphics.drawable.Drawable
 import android.view.Surface
 import androidx.annotation.ColorInt
@@ -31,7 +30,7 @@
 
     data class SnapshotSplash(
         val snapshot: Snapshot,
-        val splash: Splash,
+        val splash: Drawable?,
     ) : TaskThumbnailUiState()
 
     data class Snapshot(
@@ -39,9 +38,4 @@
         @Surface.Rotation val thumbnailRotation: Int,
         @ColorInt val backgroundColor: Int
     )
-
-    data class Splash(
-        val icon: Drawable?,
-        val size: Point,
-    )
 }
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 41aee52..0279818 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -24,11 +24,9 @@
 import android.util.AttributeSet
 import android.view.View
 import android.view.ViewOutlineProvider
-import android.widget.FrameLayout
-import android.widget.ImageView
 import androidx.annotation.ColorInt
-import androidx.core.view.isVisible
-import androidx.core.view.updateLayoutParams
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.isInvisible
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.util.ViewPool
@@ -41,6 +39,7 @@
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
 import com.android.quickstep.util.TaskCornerRadius
+import com.android.quickstep.views.FixedSizeImageView
 import com.android.systemui.shared.system.QuickStepContract
 import kotlin.math.abs
 import kotlinx.coroutines.CoroutineName
@@ -51,7 +50,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
-class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
+class TaskThumbnailView : ConstraintLayout, ViewPool.Reusable {
 
     private val viewData: TaskThumbnailViewData by RecentsDependencies.inject(this)
     private val viewModel: TaskThumbnailViewModel by RecentsDependencies.inject(this)
@@ -60,9 +59,9 @@
 
     private val scrimView: View by lazy { findViewById(R.id.task_thumbnail_scrim) }
     private val liveTileView: LiveTileView by lazy { findViewById(R.id.task_thumbnail_live_tile) }
-    private val thumbnailView: ImageView by lazy { findViewById(R.id.task_thumbnail) }
-    private val splashContainer: FrameLayout by lazy { findViewById(R.id.splash_container) }
-    private val splashIcon: ImageView by lazy { findViewById(R.id.splash_icon) }
+    private val thumbnailView: FixedSizeImageView by lazy { findViewById(R.id.task_thumbnail) }
+    private val splashBackground: View by lazy { findViewById(R.id.splash_background) }
+    private val splashIcon: FixedSizeImageView by lazy { findViewById(R.id.splash_icon) }
 
     private var uiState: TaskThumbnailUiState = Uninitialized
     private var inheritedScale: Float = 1f
@@ -107,7 +106,10 @@
             .onEach { dimProgress -> scrimView.alpha = dimProgress }
             .launchIn(viewAttachedScope)
         viewModel.splashAlpha
-            .onEach { splashAlpha -> splashContainer.alpha = splashAlpha }
+            .onEach { splashAlpha ->
+                splashBackground.alpha = splashAlpha
+                splashIcon.alpha = splashAlpha
+            }
             .launchIn(viewAttachedScope)
         viewModel.cornerRadiusProgress.onEach { invalidateOutline() }.launchIn(viewAttachedScope)
         viewModel.inheritedScale
@@ -152,15 +154,13 @@
 
     override fun setScaleX(scaleX: Float) {
         super.setScaleX(scaleX)
-        viewData.scaleX.value = scaleX
-        // Splash icon should ignore scale
+        // Splash icon should ignore scale on TTV
         splashIcon.scaleX = 1 / scaleX
     }
 
     override fun setScaleY(scaleY: Float) {
         super.setScaleY(scaleY)
-        viewData.scaleY.value = scaleY
-        // Splash icon should ignore scale
+        // Splash icon should ignore scale on TTV
         splashIcon.scaleY = 1 / scaleY
     }
 
@@ -173,9 +173,10 @@
     }
 
     private fun resetViews() {
-        liveTileView.isVisible = false
-        thumbnailView.isVisible = false
-        splashContainer.alpha = 0f
+        liveTileView.isInvisible = true
+        thumbnailView.isInvisible = true
+        splashBackground.alpha = 0f
+        splashIcon.alpha = 0f
         scrimView.alpha = 0f
         setBackgroundColor(Color.BLACK)
     }
@@ -185,25 +186,20 @@
     }
 
     private fun drawLiveWindow() {
-        liveTileView.isVisible = true
+        liveTileView.isInvisible = false
     }
 
     private fun drawSnapshotSplash(snapshotSplash: SnapshotSplash) {
         drawSnapshot(snapshotSplash.snapshot)
 
-        splashContainer.isVisible = true
-        splashContainer.setBackgroundColor(snapshotSplash.snapshot.backgroundColor)
-        splashIcon.setImageDrawable(snapshotSplash.splash.icon)
-        splashIcon.updateLayoutParams<LayoutParams> {
-            width = snapshotSplash.splash.size.x
-            height = snapshotSplash.splash.size.y
-        }
+        splashBackground.setBackgroundColor(snapshotSplash.snapshot.backgroundColor)
+        splashIcon.setImageDrawable(snapshotSplash.splash)
     }
 
     private fun drawSnapshot(snapshot: Snapshot) {
         drawBackground(snapshot.backgroundColor)
         thumbnailView.setImageBitmap(snapshot.bitmap)
-        thumbnailView.isVisible = true
+        thumbnailView.isInvisible = false
         setImageMatrix()
     }
 
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
index 1f8c0bc..3502029 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
@@ -21,6 +21,4 @@
 class TaskThumbnailViewData {
     val width = MutableStateFlow(0)
     val height = MutableStateFlow(0)
-    val scaleX = MutableStateFlow(1f)
-    val scaleY = MutableStateFlow(1f)
 }
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
index 4e29840..b1bb65e 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
@@ -19,20 +19,17 @@
 import android.annotation.ColorInt
 import android.app.ActivityTaskManager.INVALID_TASK_ID
 import android.graphics.Matrix
-import android.graphics.Point
 import androidx.core.graphics.ColorUtils
 import com.android.quickstep.recents.data.RecentTasksRepository
 import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
 import com.android.quickstep.recents.usecase.ThumbnailPositionState
 import com.android.quickstep.recents.viewmodel.RecentsViewData
-import com.android.quickstep.task.thumbnail.GetSplashSizeUseCase
 import com.android.quickstep.task.thumbnail.SplashAlphaUseCase
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
-import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Splash
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.systemui.shared.recents.model.Task
 import kotlin.math.max
@@ -55,7 +52,6 @@
     private val tasksRepository: RecentTasksRepository,
     private val getThumbnailPositionUseCase: GetThumbnailPositionUseCase,
     private val splashAlphaUseCase: SplashAlphaUseCase,
-    private val getSplashSizeUseCase: GetSplashSizeUseCase,
 ) {
     private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
     private val splashProgress = MutableStateFlow(flowOf(0f))
@@ -100,7 +96,7 @@
                     isBackgroundOnly(taskVal) ->
                         BackgroundOnly(taskVal.colorBackground.removeAlpha())
                     isSnapshotSplashState(taskVal) ->
-                        SnapshotSplash(createSnapshotState(taskVal), createSplashState(taskVal))
+                        SnapshotSplash(createSnapshotState(taskVal), taskVal.icon)
                     else -> Uninitialized
                 }
             }
@@ -139,12 +135,6 @@
         return Snapshot(bitmap, thumbnailData.rotation, task.colorBackground.removeAlpha())
     }
 
-    private fun createSplashState(task: Task): Splash {
-        val taskIcon = task.icon
-        val size = if (taskIcon == null) Point() else getSplashSizeUseCase.execute(taskIcon)
-        return Splash(taskIcon, size)
-    }
-
     @ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
 
     private companion object {
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
index 07dfc29..7a9ecf2 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
@@ -23,8 +23,6 @@
     // This is typically a View concern but it is used to invalidate rendering in other Views
     val scale = MutableStateFlow(1f)
 
-    val nonGridScale = MutableStateFlow(1f)
-
     // TODO(b/331753115): This property should not be in TaskViewData once TaskView is MVVM.
     /** Whether outline of TaskView is formed by outline thumbnail view(s). */
     val isOutlineFormedByThumbnailView: Boolean = taskViewType != TaskViewType.DESKTOP
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
index 30ee360..ec75d59 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
@@ -22,8 +22,4 @@
     fun updateScale(scale: Float) {
         taskViewData.scale.value = scale
     }
-
-    fun updateNonGridScale(nonGridScale: Float) {
-        taskViewData.nonGridScale.value = nonGridScale
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index ac4032c..e1013db 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -242,8 +242,7 @@
         WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
         ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
         ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
-        mSplitSelectStateController.setLaunchingCuj(cuj);
-        InteractionJankMonitorWrapper.begin(appPairIcon, cuj);
+        mSplitSelectStateController.setLaunchingCuj(appPairIcon, cuj);
 
         mSplitSelectStateController.findLastActiveTasksAndRunCallback(
                 Arrays.asList(app1Key, app2Key),
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ec1eeb1..b9338a3 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -28,6 +28,8 @@
 
 public class LayoutUtils {
 
+    private static final float SQUARE_ASPECT_RATIO_TOLERANCE = 0.05f;
+
     /**
      * The height for the swipe up motion
      */
@@ -61,4 +63,13 @@
             }
         }
     }
+
+    /**
+     * Returns true iff the device's aspect ratio is within
+     * {@link LayoutUtils#SQUARE_ASPECT_RATIO_TOLERANCE} of 1:1
+     */
+    public static boolean isAspectRatioSquare(float aspectRatio) {
+        return Float.compare(aspectRatio, 1f - SQUARE_ASPECT_RATIO_TOLERANCE) >= 0
+                && Float.compare(aspectRatio, 1f + SQUARE_ASPECT_RATIO_TOLERANCE) <= 0;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 0b05c2e..63fe017 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -16,6 +16,7 @@
 package com.android.quickstep.util;
 
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -33,8 +34,10 @@
 
     public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
     public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
+    public static final int INDEX_RECENTS_ATTACHED_ALPHA_ANIM =
+            AtomicAnimationFactory.NEXT_INDEX + 2;
 
-    private static final int MY_ANIM_COUNT = 2;
+    private static final int MY_ANIM_COUNT = 3;
 
     protected final CONTAINER mContainer;
 
@@ -50,6 +53,7 @@
                 ObjectAnimator alpha = ObjectAnimator.ofFloat(mContainer.getOverviewPanel(),
                         RecentsView.CONTENT_ALPHA, values);
                 return alpha;
+            case INDEX_RECENTS_ATTACHED_ALPHA_ANIM:
             case INDEX_RECENTS_TRANSLATE_X_ANIM: {
                 RecentsView rv = mContainer.getOverviewPanel();
                 return new SpringAnimationBuilder(mContainer)
@@ -57,7 +61,8 @@
                         .setDampingRatio(0.8f)
                         .setStiffness(250)
                         .setValues(values)
-                        .build(rv, ADJACENT_PAGE_HORIZONTAL_OFFSET);
+                        .build(rv, index == INDEX_RECENTS_ATTACHED_ALPHA_ANIM
+                                ? RUNNING_TASK_ATTACH_ALPHA : ADJACENT_PAGE_HORIZONTAL_OFFSET);
             }
             default:
                 return super.createStateElementAnimation(index, values);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
new file mode 100644
index 0000000..ffc345f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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 com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.quickstep.RecentsAnimationController
+import com.android.quickstep.views.DesktopTaskView
+import com.android.quickstep.views.TaskView
+import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/**
+ * Helper class for [com.android.quickstep.views.RecentsView]. This util class contains refactored
+ * and extracted functions from RecentsView to facilitate the implementation of unit tests.
+ */
+class RecentsViewUtils {
+
+    /**
+     * Sort task groups to move desktop tasks to the end of the list.
+     *
+     * @param tasks List of group tasks to be sorted.
+     * @return Sorted list of GroupTasks to be used in the RecentsView.
+     */
+    fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
+        val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
+        return otherTasks + desktopTasks
+    }
+
+    fun getFocusedTaskIndex(taskGroups: List<GroupTask>): Int {
+        // The focused task index is placed after the desktop tasks views.
+        return if (enableLargeDesktopWindowingTile()) {
+            taskGroups.count { it.taskViewType == TaskViewType.DESKTOP }
+        } else {
+            0
+        }
+    }
+
+    /**
+     * Counts [TaskView]s that are [DesktopTaskView] instances.
+     *
+     * @param taskViews List of [TaskView]s
+     */
+    fun getDesktopTaskViewCount(taskViews: List<TaskView>): Int =
+        taskViews.count { it is DesktopTaskView }
+
+    /**
+     * Returns the first TaskView that should be displayed as a large tile.
+     *
+     * @param taskViews List of [TaskView]s
+     */
+    fun getFirstLargeTaskView(taskViews: List<TaskView>): TaskView? =
+        taskViews.firstOrNull { it.isLargeTile }
+
+    fun screenshotTasks(
+        taskView: TaskView,
+        recentsAnimationController: RecentsAnimationController,
+    ): Map<Int, ThumbnailData> =
+        taskView.taskContainers.associate {
+            it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
+        }
+
+    /** Returns the current list of [TaskView] children. */
+    fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): List<TaskView> =
+        (0 until taskViewCount).map(requireTaskViewAt)
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index fa5a67a..256e29e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -731,16 +731,19 @@
         val mainRootCandidate = splitRoots.first
         // Will contain changes (1) and (2) in diagram above
         val leafRoots: List<Change> = splitRoots.second
+        // Don't rely on DP.isLeftRightSplit because if launcher is portrait apps could still
+        // launch in landscape if system auto-rotate is enabled and phone is held horizontally
+        val isLeftRightSplit = leafRoots.all { it.endAbsBounds.top == 0 }
 
         // Find the place where our left/top app window meets the divider (used for the
         // launcher side animation)
         val leftTopApp =
             leafRoots.single { change ->
-                (dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
-                    (!dp.isLeftRightSplit && change.endAbsBounds.top == 0)
+                (isLeftRightSplit && change.endAbsBounds.left == 0) ||
+                    (!isLeftRightSplit && change.endAbsBounds.top == 0)
             }
         val dividerPos =
-            if (dp.isLeftRightSplit) leftTopApp.endAbsBounds.right
+            if (isLeftRightSplit) leftTopApp.endAbsBounds.right
             else leftTopApp.endAbsBounds.bottom
 
         // Create a new floating view in Launcher, positioned above the launching icon
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index d58cb91..d982e81 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -17,14 +17,13 @@
 package com.android.quickstep.util
 
 import android.util.Log
-import android.view.WindowManager
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.TransitionInfo
 import android.window.TransitionInfo.Change
 import android.window.TransitionInfo.FLAG_FIRST_CUSTOM
 import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.wm.shell.util.SplitBounds
+import com.android.wm.shell.shared.split.SplitBounds
 import java.lang.IllegalStateException
 
 class SplitScreenUtils {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 2ff8e45..1af12f1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -55,11 +55,11 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
 import android.view.SurfaceControl;
+import android.view.View;
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.RemoteTransition;
 import android.window.RemoteTransitionStub;
@@ -97,7 +97,6 @@
 import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.SplitInstructionsView;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
@@ -150,9 +149,10 @@
 
     /**
      * Should be a constant from {@link com.android.internal.jank.Cuj} or -1, does not need to be
-     * set for all launches.
+     * set for all launches. Used in conjunction with {@link #mLaunchingViewCuj} below.
      */
     private int mLaunchCuj = -1;
+    private View mLaunchingViewCuj;
 
     private FloatingTaskView mFirstFloatingTaskView;
     private SplitInstructionsView mSplitInstructionsView;
@@ -652,7 +652,12 @@
         return mSplitAnimationController;
     }
 
-    public void setLaunchingCuj(int launchCuj) {
+    /**
+     * Set params to invoke a trace session for the given view and CUJ when we begin animating the
+     * split launch AFTER we get a response from Shell.
+     */
+    public void setLaunchingCuj(View launchingView, int launchCuj) {
+        mLaunchingViewCuj = launchingView;
         mLaunchCuj = launchCuj;
     }
 
@@ -690,6 +695,9 @@
                         && mLaunchingTaskView.getRecentsView() != null
                         && mLaunchingTaskView.getRecentsView().isTaskViewVisible(
                         mLaunchingTaskView);
+                if (mLaunchingViewCuj != null && mLaunchCuj != -1) {
+                    InteractionJankMonitorWrapper.begin(mLaunchingViewCuj, mLaunchCuj);
+                }
                 mSplitAnimationController.playSplitLaunchAnimation(
                         shouldLaunchFromTaskView ? mLaunchingTaskView : null,
                         mLaunchingIconView,
@@ -752,6 +760,7 @@
             InteractionJankMonitorWrapper.end(mLaunchCuj);
         }
         mLaunchCuj = -1;
+        mLaunchingViewCuj = null;
 
         if (mSessionInstanceIds != null) {
             mStatsLogManager.logger()
@@ -877,20 +886,22 @@
                 Log.w(TAG, "Package not found: " + packageName, e);
             }
             RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
-                    SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
-                    false /* allowMinimizeSplitScreen */);
+                    SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
 
             DesktopSplitRecentsAnimationListener listener =
                     new DesktopSplitRecentsAnimationListener(splitPosition, taskBounds);
 
-            MAIN_EXECUTOR.execute(() -> {
-                callbacks.addListener(listener);
-                UI_HELPER_EXECUTOR.execute(
-                        // Transition from app to enter stage split in launcher with
-                        // recents animation.
-                        () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
-                                mOverviewComponentObserver.getOverviewIntent(),
-                                SystemClock.uptimeMillis(), callbacks, null, null));
+            callbacks.addListener(listener);
+            UI_HELPER_EXECUTOR.execute(() -> {
+                // Transition from app to enter stage split in launcher with recents animation
+                final ActivityOptions options = ActivityOptions.makeBasic();
+                options.setPendingIntentBackgroundActivityStartMode(
+                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+                options.setTransientLaunch();
+                SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
+                        .startRecentsActivity(
+                                mOverviewComponentObserver.getOverviewIntent(), options,
+                                callbacks);
             });
         }
 
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 27fb31d..4c6e4ff 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -27,9 +27,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.SystemClock;
 
 import androidx.annotation.BinderThread;
 
@@ -84,19 +84,23 @@
             return;
         }
         RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
-                SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
-                false /* allowMinimizeSplitScreen */);
+                SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
         SplitWithKeyboardShortcutRecentsAnimationListener listener =
                 new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop);
 
         MAIN_EXECUTOR.execute(() -> {
             callbacks.addListener(listener);
-            UI_HELPER_EXECUTOR.execute(
-                    // Transition from fullscreen app to enter stage split in launcher with
-                    // recents animation.
-                    () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
-                            mOverviewComponentObserver.getOverviewIntent(),
-                            SystemClock.uptimeMillis(), callbacks, null, null));
+            UI_HELPER_EXECUTOR.execute(() -> {
+                // Transition from fullscreen app to enter stage split in launcher with
+                // recents animation
+                final ActivityOptions options = ActivityOptions.makeBasic();
+                options.setPendingIntentBackgroundActivityStartMode(
+                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+                options.setTransientLaunch();
+                SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
+                        .startRecentsActivity(mOverviewComponentObserver.getOverviewIntent(),
+                                ActivityOptions.makeBasic(), callbacks);
+            });
         });
     }
 
@@ -110,17 +114,17 @@
 
         private final boolean mLeftOrTop;
         private final Rect mTempRect = new Rect();
+        private final ActivityManager.RunningTaskInfo mRunningTaskInfo;
 
         private SplitWithKeyboardShortcutRecentsAnimationListener(boolean leftOrTop) {
             mLeftOrTop = leftOrTop;
+            mRunningTaskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
         }
 
         @Override
         public void onRecentsAnimationStart(RecentsAnimationController controller,
                 RecentsAnimationTargets targets) {
-            ActivityManager.RunningTaskInfo runningTaskInfo =
-                    ActivityManagerWrapper.getInstance().getRunningTask();
-            mController.setInitialTaskSelect(runningTaskInfo,
+            mController.setInitialTaskSelect(mRunningTaskInfo,
                     mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
                     null /* itemInfo */,
                     mLeftOrTop ? LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP
@@ -136,9 +140,9 @@
             RectF startingTaskRect = new RectF();
             final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(
                     mLauncher, mLauncher.getDragLayer(),
-                    controller.screenshotTask(runningTaskInfo.taskId).getThumbnail(),
+                    controller.screenshotTask(mRunningTaskInfo.taskId).getThumbnail(),
                     null /* icon */, startingTaskRect);
-            Task task = Task.from(new Task.TaskKey(runningTaskInfo), runningTaskInfo,
+            Task task = Task.from(new Task.TaskKey(mRunningTaskInfo), mRunningTaskInfo,
                     false /* isLocked */);
             RecentsModel.INSTANCE.get(mLauncher.getApplicationContext())
                     .getIconCache()
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 56e91ed..828322b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -39,7 +39,7 @@
 import com.android.quickstep.TaskAnimationManager;
 import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.pip.PipContentOverlay;
+import com.android.wm.shell.shared.pip.PipContentOverlay;
 
 /**
  * Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index e5c54bb..c7777d8 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -24,7 +24,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
 import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
 
@@ -535,21 +534,12 @@
 
         // If mDrawsBelowRecents is unset, no reordering will be enforced.
         if (mDrawsBelowRecents != null) {
-            // In legacy transitions, the animation leashes remain in same hierarchy in the
-            // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will
-            // conflict with layers that WM core positions (ie. the input consumers).  For shell
-            // transitions, the animation leashes are reparented to an animation container so we
-            // can bump layers as needed.
-            if (ENABLE_SHELL_TRANSITIONS) {
-                builder.setLayer(mDrawsBelowRecents
-                        ? Integer.MIN_VALUE + app.prefixOrderIndex
-                        // 1000 is an arbitrary number to give room for multiple layers.
-                        : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
-            } else {
-                builder.setLayer(mDrawsBelowRecents
-                        ? Integer.MIN_VALUE + app.prefixOrderIndex
-                        : 0);
-            }
+            // In shell transitions, the animation leashes are reparented to an animation container
+            // so we can bump layers as needed.
+            builder.setLayer(mDrawsBelowRecents
+                    ? Integer.MIN_VALUE + app.prefixOrderIndex
+                    // 1000 is an arbitrary number to give room for multiple layers.
+                    : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
index 66bff73..519ef60 100644
--- a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
@@ -16,6 +16,7 @@
 
 package com.android.quickstep.util;
 
+import android.annotation.NonNull;
 import android.os.UserHandle;
 
 import com.android.systemui.shared.recents.model.Task;
@@ -36,7 +37,7 @@
     /**
      * Called when the icon for a task changes
      */
-    default void onTaskIconChanged(String pkg, UserHandle user) {}
+    default void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {}
 
     /**
      * Called when the icon for a task changes
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 8e48f22..6db0923 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep.views
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Point
 import android.graphics.PointF
@@ -23,9 +24,9 @@
 import android.graphics.drawable.shapes.RoundRectShape
 import android.util.AttributeSet
 import android.util.Log
+import android.view.Gravity
 import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import androidx.core.content.res.ResourcesCompat
 import androidx.core.view.updateLayoutParams
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
@@ -125,11 +126,7 @@
                     snapshotView,
                     // Add snapshotView to the front after initial views e.g. icon and
                     // background.
-                    childCountAtInflation,
-                    LayoutParams(
-                        ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT
-                    )
+                    childCountAtInflation
                 )
                 TaskContainer(
                     this,
@@ -158,28 +155,37 @@
         }
     }
 
-    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
-        val containerWidth = MeasureSpec.getSize(widthMeasureSpec)
-        var containerHeight = MeasureSpec.getSize(heightMeasureSpec)
-        setMeasuredDimension(containerWidth, containerHeight)
-
+    @SuppressLint("RtlHardcoded")
+    override fun updateTaskSize(
+        lastComputedTaskSize: Rect,
+        lastComputedGridTaskSize: Rect,
+        lastComputedCarouselTaskSize: Rect
+    ) {
+        super.updateTaskSize(
+            lastComputedTaskSize,
+            lastComputedGridTaskSize,
+            lastComputedCarouselTaskSize
+        )
         if (taskContainers.isEmpty()) {
             return
         }
 
         val thumbnailTopMarginPx = container.deviceProfile.overviewTaskThumbnailTopMarginPx
-        containerHeight -= thumbnailTopMarginPx
+
+        val containerWidth = layoutParams.width
+        val containerHeight = layoutParams.height - thumbnailTopMarginPx
 
         BaseContainerInterface.getTaskDimension(mContext, container.deviceProfile, tempPointF)
+
         val windowWidth = tempPointF.x.toInt()
         val windowHeight = tempPointF.y.toInt()
         val scaleWidth = containerWidth / windowWidth.toFloat()
         val scaleHeight = containerHeight / windowHeight.toFloat()
+
         if (DEBUG) {
             Log.d(
                 TAG,
-                "onMeasure: container=[$containerWidth,$containerHeight] " +
+                "onMeasure: container=[$containerWidth,$containerHeight]" +
                     "window=[$windowWidth,$windowHeight] scale=[$scaleWidth,$scaleHeight]"
             )
         }
@@ -195,27 +201,26 @@
                         right = windowWidth / 4
                         bottom = windowHeight / 4
                     }
-            val thumbWidth = (taskSize.width() * scaleWidth).toInt()
-            val thumbHeight = (taskSize.height() * scaleHeight).toInt()
-            it.snapshotView.measure(
-                MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)
-            )
+            val positionInParent = it.task.positionInParent ?: ORIGIN
 
             // Position the task to the same position as it would be on the desktop
-            val positionInParent = it.task.positionInParent ?: ORIGIN
-            val taskX = (positionInParent.x * scaleWidth).toInt()
-            var taskY = (positionInParent.y * scaleHeight).toInt()
-            // move task down by margin size
-            taskY += thumbnailTopMarginPx
-            it.snapshotView.x = taskX.toFloat()
-            it.snapshotView.y = taskY.toFloat()
+            it.snapshotView.updateLayoutParams<LayoutParams> {
+                gravity = Gravity.LEFT or Gravity.TOP
+                width = (taskSize.width() * scaleWidth).toInt()
+                height = (taskSize.height() * scaleHeight).toInt()
+                leftMargin = (positionInParent.x * scaleWidth).toInt()
+                topMargin =
+                    (positionInParent.y * scaleHeight).toInt() +
+                        container.deviceProfile.overviewTaskThumbnailTopMarginPx
+            }
             if (DEBUG) {
-                Log.d(
-                    TAG,
-                    "onMeasure: task=${it.task.key} thumb=[$thumbWidth,$thumbHeight]" +
-                        " pos=[$taskX,$taskY]"
-                )
+                with(it.snapshotView.layoutParams as LayoutParams) {
+                    Log.d(
+                        TAG,
+                        "onMeasure: task=${it.task.key} size=[$width,$height]" +
+                            " margin=[$leftMargin,$topMargin]"
+                    )
+                }
             }
         }
     }
@@ -257,7 +262,7 @@
         }
         Log.d(
             TAG,
-            "launchTaskAnimated - launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
+            "launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
         )
 
         // Callbacks get run from recentsView for case when recents animation already running
@@ -265,11 +270,12 @@
         return endCallback
     }
 
-    override fun launchTaskAnimated() = launchTaskWithDesktopController(animated = true)
+    override fun launchAsStaticTile() = launchTaskWithDesktopController(animated = true)
 
-    override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
-        launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
-    }
+    override fun launchWithoutAnimation(
+        isQuickSwitch: Boolean,
+        callback: (launched: Boolean) -> Unit
+    ) = launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
 
     // Desktop tile can't be in split screen
     override fun confirmSecondSplitSelectApp(): Boolean = false
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
deleted file mode 100644
index 9f268a0..0000000
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Copyright (C) 2018 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.views;
-
-import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
-
-import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
-
-import android.app.ActivityOptions;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.AppUsageLimit;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.icu.text.MeasureFormat;
-import android.icu.text.MeasureFormat.FormatWidth;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Pair;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.quickstep.TaskUtils;
-import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.Locale;
-
-public final class DigitalWellBeingToast {
-
-    private static final float THRESHOLD_LEFT_ICON_ONLY = 0.4f;
-    private static final float THRESHOLD_RIGHT_ICON_ONLY = 0.6f;
-
-    /** Will span entire width of taskView with full text */
-    private static final int SPLIT_BANNER_FULLSCREEN = 0;
-    /** Used for grid task view, only showing icon and time */
-    private static final int SPLIT_GRID_BANNER_LARGE = 1;
-    /** Used for grid task view, only showing icon */
-    private static final int SPLIT_GRID_BANNER_SMALL = 2;
-
-    @IntDef(value = {
-            SPLIT_BANNER_FULLSCREEN,
-            SPLIT_GRID_BANNER_LARGE,
-            SPLIT_GRID_BANNER_SMALL,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface SplitBannerConfig {
-    }
-
-    static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
-    static final int MINUTE_MS = 60000;
-
-    private static final String TAG = "DigitalWellBeingToast";
-
-    private final RecentsViewContainer mContainer;
-    private final TaskView mTaskView;
-    private final LauncherApps mLauncherApps;
-
-    private final int mBannerHeight;
-
-    private Task mTask;
-    private boolean mHasLimit;
-
-    private long mAppRemainingTimeMs;
-    @Nullable
-    private View mBanner;
-    private ViewOutlineProvider mOldBannerOutlineProvider;
-    private float mBannerOffsetPercentage;
-    @Nullable
-    private SplitBounds mSplitBounds;
-    private float mSplitOffsetTranslationY;
-    private float mSplitOffsetTranslationX;
-
-    private boolean mIsDestroyed = false;
-
-    public DigitalWellBeingToast(RecentsViewContainer container, TaskView taskView) {
-        mContainer = container;
-        mTaskView = taskView;
-        mLauncherApps = container.asContext().getSystemService(LauncherApps.class);
-        mBannerHeight = container.asContext().getResources().getDimensionPixelSize(
-                R.dimen.digital_wellbeing_toast_height);
-    }
-
-    private void setNoLimit() {
-        mHasLimit = false;
-        mTaskView.setContentDescription(mTask.titleDescription);
-        replaceBanner(null);
-        mAppRemainingTimeMs = -1;
-    }
-
-    private void setLimit(long appUsageLimitTimeMs, long appRemainingTimeMs) {
-        mAppRemainingTimeMs = appRemainingTimeMs;
-        mHasLimit = true;
-        TextView toast = mContainer.getViewCache().getView(R.layout.digital_wellbeing_toast,
-                mContainer.asContext(), mTaskView);
-        toast.setText(prefixTextWithIcon(mContainer.asContext(), R.drawable.ic_hourglass_top,
-                getText()));
-        toast.setOnClickListener(this::openAppUsageSettings);
-        replaceBanner(toast);
-
-        mTaskView.setContentDescription(
-                getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs));
-    }
-
-    public String getText() {
-        return getText(mAppRemainingTimeMs, false /* forContentDesc */);
-    }
-
-    public boolean hasLimit() {
-        return mHasLimit;
-    }
-
-    public void initialize(Task task) {
-        if (mIsDestroyed) {
-            throw new IllegalStateException("Cannot re-initialize a destroyed toast");
-        }
-        mTask = task;
-        ORDERED_BG_EXECUTOR.execute(() -> {
-            AppUsageLimit usageLimit = null;
-            try {
-                usageLimit = mLauncherApps.getAppUsageLimit(
-                        mTask.getTopComponent().getPackageName(),
-                        UserHandle.of(mTask.key.userId));
-            } catch (Exception e) {
-                Log.e(TAG, "Error initializing digital well being toast", e);
-            }
-            final long appUsageLimitTimeMs =
-                    usageLimit != null ? usageLimit.getTotalUsageLimit() : -1;
-            final long appRemainingTimeMs =
-                    usageLimit != null ? usageLimit.getUsageRemaining() : -1;
-
-            mTaskView.post(() -> {
-                if (mIsDestroyed) {
-                    return;
-                }
-                if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
-                    setNoLimit();
-                } else {
-                    setLimit(appUsageLimitTimeMs, appRemainingTimeMs);
-                }
-            });
-        });
-    }
-
-    /**
-     * Mark the DWB toast as destroyed and remove banner from TaskView.
-     */
-    public void destroy() {
-        mIsDestroyed = true;
-        mTaskView.post(() -> replaceBanner(null));
-    }
-
-    public void setSplitBounds(@Nullable SplitBounds splitBounds) {
-        mSplitBounds = splitBounds;
-    }
-
-    private @SplitBannerConfig int getSplitBannerConfig() {
-        if (mSplitBounds == null
-                || !mContainer.getDeviceProfile().isTablet
-                || mTaskView.isFocusedTask()) {
-            return SPLIT_BANNER_FULLSCREEN;
-        }
-
-        // For portrait grid only height of task changes, not width. So we keep the text the same
-        if (!mContainer.getDeviceProfile().isLeftRightSplit) {
-            return SPLIT_GRID_BANNER_LARGE;
-        }
-
-        // For landscape grid, for 30% width we only show icon, otherwise show icon and time
-        if (mTask.key.id == mSplitBounds.leftTopTaskId) {
-            return mSplitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY
-                    ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
-        } else {
-            return mSplitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY
-                    ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
-        }
-    }
-
-    private String getReadableDuration(
-            Duration duration,
-            @StringRes int durationLessThanOneMinuteStringId) {
-        int hours = Math.toIntExact(duration.toHours());
-        int minutes = Math.toIntExact(duration.minusHours(hours).toMinutes());
-
-        // Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
-        if (hours > 0 && minutes > 0) {
-            return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.NARROW)
-                    .formatMeasures(
-                            new Measure(hours, MeasureUnit.HOUR),
-                            new Measure(minutes, MeasureUnit.MINUTE));
-        }
-
-        // Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
-        if (hours > 0) {
-            return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
-                    new Measure(hours, MeasureUnit.HOUR));
-        }
-
-        // Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
-        if (minutes > 0) {
-            return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
-                    new Measure(minutes, MeasureUnit.MINUTE));
-        }
-
-        // Use a specific string for usage less than one minute but non-zero.
-        if (duration.compareTo(Duration.ZERO) > 0) {
-            return mContainer.asContext().getString(durationLessThanOneMinuteStringId);
-        }
-
-        // Otherwise, return 0-minute string.
-        return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
-                new Measure(0, MeasureUnit.MINUTE));
-    }
-
-    /**
-     * Returns text to show for the banner depending on {@link #getSplitBannerConfig()}
-     * If {@param forContentDesc} is {@code true}, this will always return the full
-     * string corresponding to {@link #SPLIT_BANNER_FULLSCREEN}
-     */
-    private String getText(long remainingTime, boolean forContentDesc) {
-        final Duration duration = Duration.ofMillis(
-                remainingTime > MINUTE_MS ?
-                        (remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS :
-                        remainingTime);
-        String readableDuration = getReadableDuration(duration,
-                R.string.shorter_duration_less_than_one_minute
-                /* forceFormatWidth */);
-        @SplitBannerConfig int splitBannerConfig = getSplitBannerConfig();
-        if (forContentDesc || splitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
-            return mContainer.asContext().getString(
-                    R.string.time_left_for_app,
-                    readableDuration);
-        }
-
-        if (splitBannerConfig == SPLIT_GRID_BANNER_SMALL) {
-            // show no text
-            return "";
-        } else { // SPLIT_GRID_BANNER_LARGE
-            // only show time
-            return readableDuration;
-        }
-    }
-
-    public void openAppUsageSettings(View view) {
-        final Intent intent = new Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE)
-                .putExtra(Intent.EXTRA_PACKAGE_NAME,
-                        mTask.getTopComponent().getPackageName()).addFlags(
-                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        try {
-            final RecentsViewContainer container =
-                    RecentsViewContainer.containerFromContext(view.getContext());
-            final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(
-                    view, 0, 0,
-                    view.getWidth(), view.getHeight());
-            container.asContext().startActivity(intent, options.toBundle());
-
-            // TODO: add WW logging on the app usage settings click.
-        } catch (ActivityNotFoundException e) {
-            Log.e(TAG, "Failed to open app usage settings for task "
-                    + mTask.getTopComponent().getPackageName(), e);
-        }
-    }
-
-    private String getContentDescriptionForTask(
-            Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) {
-        return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ?
-                mContainer.asContext().getString(
-                        R.string.task_contents_description_with_remaining_time,
-                        task.titleDescription,
-                        getText(appRemainingTimeMs, true /* forContentDesc */)) :
-                task.titleDescription;
-    }
-
-    private void replaceBanner(@Nullable View view) {
-        resetOldBanner();
-        setBanner(view);
-    }
-
-    private void resetOldBanner() {
-        if (mBanner != null) {
-            mBanner.setOutlineProvider(mOldBannerOutlineProvider);
-            mTaskView.removeView(mBanner);
-            mBanner.setOnClickListener(null);
-            mContainer.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner);
-        }
-    }
-
-    private void setBanner(@Nullable View view) {
-        mBanner = view;
-        if (mBanner != null && mTaskView.getRecentsView() != null) {
-            setupAndAddBanner();
-            setBannerOutline();
-        }
-    }
-
-    private void setupAndAddBanner() {
-        FrameLayout.LayoutParams layoutParams =
-                (FrameLayout.LayoutParams) mBanner.getLayoutParams();
-        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
-        layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
-                mTaskView.getFirstSnapshotView().getLayoutParams()).bottomMargin;
-        RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
-        Pair<Float, Float> translations = orientationHandler
-                .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
-                        mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
-                        mTaskView.getSnapshotViews(), mTask.key.id, mBanner);
-        mSplitOffsetTranslationX = translations.first;
-        mSplitOffsetTranslationY = translations.second;
-        updateTranslationY();
-        updateTranslationX();
-        mTaskView.addView(mBanner);
-    }
-
-    private void setBannerOutline() {
-        // TODO(b\273367585) to investigate why mBanner.getOutlineProvider() can be null
-        mOldBannerOutlineProvider = mBanner.getOutlineProvider() != null
-                ? mBanner.getOutlineProvider()
-                : ViewOutlineProvider.BACKGROUND;
-
-        mBanner.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                mOldBannerOutlineProvider.getOutline(view, outline);
-                float verticalTranslation = -view.getTranslationY() + mSplitOffsetTranslationY;
-                outline.offset(0, Math.round(verticalTranslation));
-            }
-        });
-        mBanner.setClipToOutline(true);
-    }
-
-    void updateBannerOffset(float offsetPercentage) {
-        if (mBannerOffsetPercentage != offsetPercentage) {
-            mBannerOffsetPercentage = offsetPercentage;
-            if (mBanner != null) {
-                updateTranslationY();
-                mBanner.invalidateOutline();
-            }
-        }
-    }
-
-    private void updateTranslationY() {
-        if (mBanner == null) {
-            return;
-        }
-
-        mBanner.setTranslationY(
-                (mBannerOffsetPercentage * mBannerHeight) + mSplitOffsetTranslationY);
-    }
-
-    private void updateTranslationX() {
-        if (mBanner == null) {
-            return;
-        }
-
-        mBanner.setTranslationX(mSplitOffsetTranslationX);
-    }
-
-    void setBannerColorTint(int color, float amount) {
-        if (mBanner == null) {
-            return;
-        }
-        if (amount == 0) {
-            mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
-        }
-        Paint layerPaint = new Paint();
-        layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
-        mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
-        mBanner.setLayerPaint(layerPaint);
-    }
-
-    void setBannerVisibility(int visibility) {
-        if (mBanner == null) {
-            return;
-        }
-
-        mBanner.setVisibility(visibility);
-    }
-
-    private int getAccessibilityActionId() {
-        return (mSplitBounds != null
-                && mSplitBounds.rightBottomTaskId == mTask.key.id)
-                ? R.id.action_digital_wellbeing_bottom_right
-                : R.id.action_digital_wellbeing_top_left;
-    }
-
-    @Nullable
-    public AccessibilityNodeInfo.AccessibilityAction getDWBAccessibilityAction() {
-        if (!hasLimit()) {
-            return null;
-        }
-
-        Context context = mContainer.asContext();
-        String label =
-                (mTaskView.containsMultipleTasks())
-                        ? context.getString(
-                        R.string.split_app_usage_settings,
-                        TaskUtils.getTitle(context, mTask)
-                ) : context.getString(R.string.accessibility_app_usage_settings);
-        return new AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label);
-    }
-
-    public boolean handleAccessibilityAction(int action) {
-        if (getAccessibilityActionId() == action) {
-            openAppUsageSettings(mTaskView);
-            return true;
-        } else {
-            return false;
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
new file mode 100644
index 0000000..7b97c23
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2018 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.views
+
+import android.annotation.SuppressLint
+import android.app.ActivityOptions
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.LauncherApps.AppUsageLimit
+import android.graphics.Outline
+import android.graphics.Paint
+import android.icu.text.MeasureFormat
+import android.icu.util.Measure
+import android.icu.util.MeasureUnit
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.view.ViewOutlineProvider
+import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
+import androidx.core.view.isVisible
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.quickstep.TaskUtils
+import com.android.systemui.shared.recents.model.Task
+import java.time.Duration
+import java.util.Locale
+
+@SuppressLint("AppCompatCustomView")
+class DigitalWellBeingToast
+@JvmOverloads
+constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0
+) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+    private val recentsViewContainer =
+        RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+
+    private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java)
+
+    private val bannerHeight =
+        context.resources.getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height)
+
+    private lateinit var task: Task
+    private lateinit var taskView: TaskView
+    private lateinit var snapshotView: View
+    @StagePosition private var stagePosition = STAGE_POSITION_UNDEFINED
+
+    private var appRemainingTimeMs: Long = 0
+    private var splitOffsetTranslationY = 0f
+        set(value) {
+            if (field != value) {
+                field = value
+                updateTranslationY()
+            }
+        }
+
+    private var isDestroyed = false
+
+    var hasLimit = false
+    var splitBounds: SplitConfigurationOptions.SplitBounds? = null
+    var bannerOffsetPercentage = 0f
+        set(value) {
+            if (field != value) {
+                field = value
+                updateTranslationY()
+            }
+        }
+
+    init {
+        setOnClickListener(::openAppUsageSettings)
+        outlineProvider =
+            object : ViewOutlineProvider() {
+                override fun getOutline(view: View, outline: Outline) {
+                    BACKGROUND.getOutline(view, outline)
+                    val verticalTranslation = splitOffsetTranslationY - translationY
+                    outline.offset(0, Math.round(verticalTranslation))
+                }
+            }
+        clipToOutline = true
+    }
+
+    private fun setNoLimit() {
+        isVisible = false
+        hasLimit = false
+        appRemainingTimeMs = -1
+        setContentDescription(appUsageLimitTimeMs = -1, appRemainingTimeMs = -1)
+    }
+
+    private fun setLimit(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
+        isVisible = true
+        hasLimit = true
+        this.appRemainingTimeMs = appRemainingTimeMs
+        setContentDescription(appUsageLimitTimeMs, appRemainingTimeMs)
+        text = Utilities.prefixTextWithIcon(context, R.drawable.ic_hourglass_top, getBannerText())
+    }
+
+    private fun setContentDescription(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
+        val contentDescription =
+            getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs)
+        snapshotView.contentDescription = contentDescription
+    }
+
+    fun initialize() {
+        check(!isDestroyed) { "Cannot re-initialize a destroyed toast" }
+        setupTranslations()
+        Executors.ORDERED_BG_EXECUTOR.execute {
+            var usageLimit: AppUsageLimit? = null
+            try {
+                usageLimit =
+                    launcherApps?.getAppUsageLimit(
+                        task.topComponent.packageName,
+                        UserHandle.of(task.key.userId)
+                    )
+            } catch (e: Exception) {
+                Log.e(TAG, "Error initializing digital well being toast", e)
+            }
+            val appUsageLimitTimeMs = usageLimit?.totalUsageLimit ?: -1
+            val appRemainingTimeMs = usageLimit?.usageRemaining ?: -1
+
+            taskView.post {
+                if (isDestroyed) return@post
+                if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
+                    setNoLimit()
+                } else {
+                    setLimit(appUsageLimitTimeMs, appRemainingTimeMs)
+                }
+            }
+        }
+    }
+
+    /** Bind the DWB toast to its dependencies. */
+    fun bind(
+        task: Task,
+        taskView: TaskView,
+        snapshotView: View,
+        @StagePosition stagePosition: Int
+    ) {
+        this.task = task
+        this.taskView = taskView
+        this.snapshotView = snapshotView
+        this.stagePosition = stagePosition
+        isDestroyed = false
+    }
+
+    /** Mark the DWB toast as destroyed and hide it. */
+    fun destroy() {
+        isVisible = false
+        isDestroyed = true
+    }
+
+    private fun getSplitBannerConfig(): SplitBannerConfig {
+        val splitBounds = splitBounds
+        return when {
+            splitBounds == null ||
+                !recentsViewContainer.deviceProfile.isTablet ||
+                taskView.isLargeTile -> SplitBannerConfig.SPLIT_BANNER_FULLSCREEN
+            // For portrait grid only height of task changes, not width. So we keep the text the
+            // same
+            !recentsViewContainer.deviceProfile.isLeftRightSplit ->
+                SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+            // For landscape grid, for 30% width we only show icon, otherwise show icon and time
+            task.key.id == splitBounds.leftTopTaskId ->
+                if (splitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY)
+                    SplitBannerConfig.SPLIT_GRID_BANNER_SMALL
+                else SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+            else ->
+                if (splitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY)
+                    SplitBannerConfig.SPLIT_GRID_BANNER_SMALL
+                else SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+        }
+    }
+
+    private fun getReadableDuration(
+        duration: Duration,
+        @StringRes durationLessThanOneMinuteStringId: Int
+    ): String {
+        val hours = Math.toIntExact(duration.toHours())
+        val minutes = Math.toIntExact(duration.minusHours(hours.toLong()).toMinutes())
+        return when {
+            // Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
+            hours > 0 && minutes > 0 ->
+                MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.NARROW)
+                    .formatMeasures(
+                        Measure(hours, MeasureUnit.HOUR),
+                        Measure(minutes, MeasureUnit.MINUTE)
+                    )
+            // Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
+            hours > 0 ->
+                MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+                    .formatMeasures(Measure(hours, MeasureUnit.HOUR))
+            // Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
+            minutes > 0 ->
+                MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+                    .formatMeasures(Measure(minutes, MeasureUnit.MINUTE))
+            // Use a specific string for usage less than one minute but non-zero.
+            duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId)
+            // Otherwise, return 0-minute string.
+            else ->
+                MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+                    .formatMeasures(Measure(0, MeasureUnit.MINUTE))
+        }
+    }
+
+    /**
+     * Returns text to show for the banner depending on [.getSplitBannerConfig] If {@param
+     * forContentDesc} is `true`, this will always return the full string corresponding to
+     * [.SPLIT_BANNER_FULLSCREEN]
+     */
+    @JvmOverloads
+    @VisibleForTesting
+    fun getBannerText(
+        remainingTime: Long = appRemainingTimeMs,
+        forContentDesc: Boolean = false
+    ): String {
+        val duration =
+            Duration.ofMillis(
+                if (remainingTime > MINUTE_MS)
+                    (remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS
+                else remainingTime
+            )
+        val readableDuration =
+            getReadableDuration(
+                duration,
+                R.string.shorter_duration_less_than_one_minute /* forceFormatWidth */
+            )
+        val splitBannerConfig = getSplitBannerConfig()
+        return when {
+            forContentDesc || splitBannerConfig == SplitBannerConfig.SPLIT_BANNER_FULLSCREEN ->
+                context.getString(R.string.time_left_for_app, readableDuration)
+            // show no text
+            splitBannerConfig == SplitBannerConfig.SPLIT_GRID_BANNER_SMALL -> ""
+            // SPLIT_GRID_BANNER_LARGE only show time
+            else -> readableDuration
+        }
+    }
+
+    private fun openAppUsageSettings(view: View) {
+        val intent =
+            Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE)
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, task.topComponent.packageName)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        try {
+            val options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.width, view.height)
+            context.startActivity(intent, options.toBundle())
+
+            // TODO: add WW logging on the app usage settings click.
+        } catch (e: ActivityNotFoundException) {
+            Log.e(
+                TAG,
+                "Failed to open app usage settings for task " + task.topComponent.packageName,
+                e
+            )
+        }
+    }
+
+    private fun getContentDescriptionForTask(
+        task: Task,
+        appUsageLimitTimeMs: Long,
+        appRemainingTimeMs: Long
+    ): String? =
+        if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0)
+            context.getString(
+                R.string.task_contents_description_with_remaining_time,
+                task.titleDescription,
+                getBannerText(appRemainingTimeMs, true /* forContentDesc */)
+            )
+        else task.titleDescription
+
+    fun setupLayout() {
+        val snapshotWidth: Int
+        val snapshotHeight: Int
+        val splitBounds = splitBounds
+        if (splitBounds == null) {
+            snapshotWidth = taskView.layoutParams.width
+            snapshotHeight =
+                taskView.layoutParams.height -
+                    recentsViewContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+        } else {
+            val groupedTaskSize =
+                taskView.pagedOrientationHandler.getGroupedTaskViewSizes(
+                    recentsViewContainer.deviceProfile,
+                    splitBounds,
+                    taskView.layoutParams.width,
+                    taskView.layoutParams.height
+                )
+            if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+                snapshotWidth = groupedTaskSize.first.x
+                snapshotHeight = groupedTaskSize.first.y
+            } else {
+                snapshotWidth = groupedTaskSize.second.x
+                snapshotHeight = groupedTaskSize.second.y
+            }
+        }
+        taskView.pagedOrientationHandler.updateDwbBannerLayout(
+            taskView.layoutParams.width,
+            taskView.layoutParams.height,
+            taskView is GroupedTaskView,
+            recentsViewContainer.deviceProfile,
+            snapshotWidth,
+            snapshotHeight,
+            this
+        )
+    }
+
+    private fun setupTranslations() {
+        val (translationX, translationY) =
+            taskView.pagedOrientationHandler.getDwbBannerTranslations(
+                taskView.layoutParams.width,
+                taskView.layoutParams.height,
+                splitBounds,
+                recentsViewContainer.deviceProfile,
+                taskView.snapshotViews,
+                task.key.id,
+                this
+            )
+        this.translationX = translationX
+        this.splitOffsetTranslationY = translationY
+    }
+
+    private fun updateTranslationY() {
+        translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY
+        invalidateOutline()
+    }
+
+    fun setColorTint(color: Int, amount: Float) {
+        if (amount == 0f) {
+            setLayerType(View.LAYER_TYPE_NONE, null)
+        }
+        val layerPaint = Paint()
+        layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount))
+        setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint)
+        setLayerPaint(layerPaint)
+    }
+
+    private fun getAccessibilityActionId(): Int =
+        if (splitBounds?.rightBottomTaskId == task.key.id)
+            R.id.action_digital_wellbeing_bottom_right
+        else R.id.action_digital_wellbeing_top_left
+
+    fun getDWBAccessibilityAction(): AccessibilityNodeInfo.AccessibilityAction? {
+        if (!hasLimit) return null
+        val label =
+            if (taskView.containsMultipleTasks())
+                context.getString(
+                    R.string.split_app_usage_settings,
+                    TaskUtils.getTitle(context, task)
+                )
+            else context.getString(R.string.accessibility_app_usage_settings)
+        return AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label)
+    }
+
+    fun handleAccessibilityAction(action: Int): Boolean {
+        if (getAccessibilityActionId() != action) return false
+        openAppUsageSettings(taskView)
+        return true
+    }
+
+    companion object {
+        private const val THRESHOLD_LEFT_ICON_ONLY = 0.4f
+        private const val THRESHOLD_RIGHT_ICON_ONLY = 0.6f
+
+        enum class SplitBannerConfig {
+            /** Will span entire width of taskView with full text */
+            SPLIT_BANNER_FULLSCREEN,
+            /** Used for grid task view, only showing icon and time */
+            SPLIT_GRID_BANNER_LARGE,
+            /** Used for grid task view, only showing icon */
+            SPLIT_GRID_BANNER_SMALL
+        }
+
+        val OPEN_APP_USAGE_SETTINGS_TEMPLATE: Intent = Intent(Settings.ACTION_APP_USAGE_SETTINGS)
+        const val MINUTE_MS: Int = 60000
+
+        private const val TAG = "DigitalWellBeingToast"
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt b/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt
new file mode 100644
index 0000000..c893016
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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.views
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.ViewGroup
+import android.widget.ImageView
+
+/**
+ * An [ImageView] that does not requestLayout() unless setLayoutParams is called.
+ *
+ * This is useful, particularly during animations, for [ImageView]s that are not supposed to be
+ * resized.
+ */
+@SuppressLint("AppCompatCustomView")
+class FixedSizeImageView : ImageView {
+    private var shouldRequestLayoutOnChanges = false
+
+    constructor(context: Context) : super(context)
+
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+    constructor(
+        context: Context,
+        attrs: AttributeSet?,
+        defStyleAttr: Int,
+    ) : super(context, attrs, defStyleAttr)
+
+    override fun setLayoutParams(params: ViewGroup.LayoutParams?) {
+        shouldRequestLayoutOnChanges = true
+        super.setLayoutParams(params)
+        shouldRequestLayoutOnChanges = false
+    }
+
+    override fun requestLayout() {
+        if (shouldRequestLayoutOnChanges) {
+            super.requestLayout()
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index a046c42..3fd1a6b 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -115,6 +115,7 @@
                     R.id.snapshot,
                     R.id.icon,
                     R.id.show_windows,
+                    R.id.digital_wellbeing_toast,
                     STAGE_POSITION_TOP_OR_LEFT,
                     taskOverlayFactory
                 ),
@@ -123,6 +124,7 @@
                     R.id.bottomright_snapshot,
                     R.id.bottomRight_icon,
                     R.id.show_windows_right,
+                    R.id.bottomRight_digital_wellbeing_toast,
                     STAGE_POSITION_BOTTOM_OR_RIGHT,
                     taskOverlayFactory
                 )
@@ -130,7 +132,7 @@
         taskContainers.forEach { it.bind() }
 
         this.splitBoundsConfig = splitBoundsConfig
-        taskContainers.forEach { it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig) }
+        taskContainers.forEach { it.digitalWellBeingToast?.splitBounds = splitBoundsConfig }
         setOrientationState(orientedState)
     }
 
@@ -210,17 +212,13 @@
     fun updateSplitBoundsConfig(splitBounds: SplitConfigurationOptions.SplitBounds?) {
         splitBoundsConfig = splitBounds
         taskContainers.forEach {
-            it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig)
-            it.digitalWellBeingToast?.initialize(it.task)
+            it.digitalWellBeingToast?.splitBounds = splitBoundsConfig
+            it.digitalWellBeingToast?.initialize()
         }
         invalidate()
     }
 
-    override fun launchTaskAnimated(): RunnableList? {
-        if (taskContainers.isEmpty()) {
-            Log.d(TAG, "launchTaskAnimated - task is not bound")
-            return null
-        }
+    override fun launchAsStaticTile(): RunnableList? {
         val recentsView = recentsView ?: return null
         val endCallback = RunnableList()
         // Callbacks run from remote animation when recents animation not currently running
@@ -239,8 +237,11 @@
         return endCallback
     }
 
-    override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
-        launchTaskInternal(isQuickSwitch, false, callback /*launchingExistingTaskview*/)
+    override fun launchWithoutAnimation(
+        isQuickSwitch: Boolean,
+        callback: (launched: Boolean) -> Unit
+    ) {
+        launchTaskInternal(isQuickSwitch, launchingExistingTaskView = false, callback)
     }
 
     /**
@@ -264,7 +265,10 @@
                 isQuickSwitch,
                 snapPosition
             )
-            Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}")
+            Log.d(
+                TAG,
+                "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}, launchingExistingTaskView: $launchingExistingTaskView"
+            )
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index d9468c7..4a2be2a 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -274,7 +274,9 @@
     }
 
     private void updateActionButtonsVisibility() {
-        assert mDp != null;
+        if (mDp == null) {
+            return;
+        }
         boolean showSingleTaskActions = !mIsGroupedTask;
         boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
         Log.d(TAG, "updateActionButtonsVisibility() called: showSingleTaskActions = ["
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bb2a12f..f8a0f45 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -36,7 +36,9 @@
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
+import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile;
 import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
@@ -211,6 +213,7 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.RecentsAtomicAnimationFactory;
 import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.RecentsViewUtils;
 import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
 import com.android.quickstep.util.SplitAnimationTimings;
 import com.android.quickstep.util.SplitSelectStateController;
@@ -229,9 +232,9 @@
 import com.android.systemui.shared.system.PackageManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
 import com.android.wm.shell.common.pip.IPipAnimationListener;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
 
 import kotlin.Unit;
 
@@ -254,8 +257,8 @@
  * @param <CONTAINER_TYPE> : the container that should host recents view
  * @param <STATE_TYPE>     : the type of base state that will be used
  */
-
-public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewContainer,
+public abstract class RecentsView<
+        CONTAINER_TYPE extends Context & RecentsViewContainer,
         STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
         TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
         TaskVisualsChangeListener {
@@ -318,6 +321,27 @@
                 }
             };
 
+    public static final FloatProperty<RecentsView> RUNNING_TASK_ATTACH_ALPHA =
+            new FloatProperty<RecentsView>("runningTaskAttachAlpha") {
+                @Override
+                public void setValue(RecentsView recentsView, float v) {
+                    TaskView runningTask = recentsView.getRunningTaskView();
+                    if (runningTask == null) {
+                        return;
+                    }
+                    runningTask.setAttachAlpha(v);
+                }
+
+                @Override
+                public Float get(RecentsView recentsView) {
+                    TaskView runningTask = recentsView.getRunningTaskView();
+                    if (runningTask == null) {
+                        return null;
+                    }
+                    return runningTask.getAttachAlpha();
+                }
+            };
+
     public static final int SCROLL_VIBRATION_PRIMITIVE =
             Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
     public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
@@ -611,13 +635,16 @@
         @Override
         public void onTaskRemoved(int taskId) {
             if (!mHandleTaskStackChanges) {
+                Log.d(TAG, "onTaskRemoved: " + taskId + ", not handling task stack changes");
                 return;
             }
 
             TaskView taskView = getTaskViewByTaskId(taskId);
             if (taskView == null) {
+                Log.d(TAG, "onTaskRemoved: " + taskId + ", no associated TaskView");
                 return;
             }
+            Log.d(TAG, "onTaskRemoved: " + taskId);
             Task.TaskKey taskKey = taskView.getFirstTask().key;
             UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
                     () -> PackageManagerWrapper.getInstance()
@@ -656,7 +683,7 @@
     protected boolean mRunningTaskTileHidden;
     @Nullable
     private Task[] mTmpRunningTasks;
-    protected int mFocusedTaskViewId = -1;
+    protected int mFocusedTaskViewId = INVALID_TASK_ID;
 
     private boolean mTaskIconScaledDown = false;
     private boolean mRunningTaskShowScreenshot = false;
@@ -813,7 +840,8 @@
     private boolean mAnyTaskHasBeenDismissed;
 
     private final RecentsViewModel mRecentsViewModel;
-    private final RecentsViewHelper mHelper;
+    private final RecentsViewModelHelper mHelper;
+    private final RecentsViewUtils mUtils = new RecentsViewUtils();
 
     public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             BaseContainerInterface sizeStrategy) {
@@ -835,7 +863,7 @@
                     recentsDependencies.inject(RecentTasksRepository.class),
                     recentsDependencies.inject(RecentsViewData.class)
             );
-            mHelper = new RecentsViewHelper(mRecentsViewModel);
+            mHelper = new RecentsViewModelHelper(mRecentsViewModel);
 
             recentsDependencies.provide(RecentsRotationStateRepository.class,
                     () -> new RecentsRotationStateRepositoryImpl(mOrientationState));
@@ -1053,7 +1081,6 @@
     @Nullable
     public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
         if (enableRefactorTaskThumbnail()) {
-            mHelper.onTaskThumbnailChanged(taskId, thumbnailData);
             return null;
         }
         if (mHandleTaskStackChanges) {
@@ -1074,16 +1101,14 @@
     }
 
     @Override
-    public void onTaskIconChanged(String pkg, UserHandle user) {
-        // TODO(b/342560598): Listen in TaskRepository and reload.
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView tv = requireTaskViewAt(i);
-            Task task = tv.getFirstTask();
+    public void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {
+        for (TaskView taskView : getTaskViews()) {
+            Task task = taskView.getFirstTask();
             if (pkg.equals(task.key.getPackageName()) && task.key.userId == user.getIdentifier()) {
                 task.icon = null;
-                if (tv.getTaskContainers().stream().anyMatch(
+                if (taskView.getTaskContainers().stream().anyMatch(
                         container -> container.getIconView().getDrawable() != null)) {
-                    tv.onTaskListVisibilityChanged(true /* visible */);
+                    taskView.onTaskListVisibilityChanged(true /* visible */);
                 }
             }
         }
@@ -1472,8 +1497,7 @@
             return null;
         }
 
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             if (taskView.containsTaskId(taskId)) {
                 return taskView;
             }
@@ -1494,8 +1518,7 @@
         int[] taskIdsCopy = Arrays.copyOf(taskIds, taskIds.length);
         Arrays.sort(taskIdsCopy);
 
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             int[] taskViewIdsCopy = taskView.getTaskIds();
             Arrays.sort(taskViewIdsCopy);
             if (Arrays.equals(taskIdsCopy, taskViewIdsCopy)) {
@@ -1531,9 +1554,7 @@
      */
     public void setTaskBorderEnabled(boolean enabled) {
         mBorderEnabled = enabled;
-        int taskCount = getTaskViewCount();
-        for (int i = 0; i < taskCount; i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             taskView.setBorderEnabled(enabled);
         }
         mClearAllButton.setBorderEnabled(enabled);
@@ -1600,9 +1621,7 @@
         super.onTouchEvent(ev);
 
         if (showAsGrid()) {
-            int taskCount = getTaskViewCount();
-            for (int i = 0; i < taskCount; i++) {
-                TaskView taskView = requireTaskViewAt(i);
+            for (TaskView taskView : getTaskViews()) {
                 if (isTaskViewVisible(taskView) && taskView.offerTouchToChildren(ev)) {
                     // Keep consuming events to pass to delegate
                     return true;
@@ -1685,10 +1704,10 @@
                 }
                 TaskView taskView = getTaskViewAt(mNextPage);
                 // Snap to fully visible focused task and clear all button.
-                boolean shouldSnapToFocusedTask = taskView != null && taskView.isFocusedTask()
+                boolean shouldSnapToLargeTask = taskView != null && taskView.isLargeTile()
                         && isTaskViewFullyVisible(taskView);
                 boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton);
-                if (!shouldSnapToFocusedTask && !shouldSnapToClearAll) {
+                if (!shouldSnapToLargeTask && !shouldSnapToClearAll) {
                     return;
                 }
             }
@@ -1748,7 +1767,9 @@
             return;
         }
 
-        if (mCurrentPage == 0) {
+        int frontIndex = enableLargeDesktopWindowingTile() ? getDesktopTaskViewCount() : 0;
+
+        if (mCurrentPage <= frontIndex) {
             return;
         }
 
@@ -1760,8 +1781,9 @@
         removeView(runningTaskView);
         mMovingTaskView = null;
         runningTaskView.resetPersistentViewTransforms();
-        addView(runningTaskView, 0);
-        setCurrentPage(0);
+
+        addView(runningTaskView, frontIndex);
+        setCurrentPage(frontIndex);
 
         updateTaskSize();
     }
@@ -1779,7 +1801,8 @@
 
     protected void applyLoadPlan(List<GroupTask> taskGroups) {
         if (mPendingAnimation != null) {
-            mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
+            final List<GroupTask> finalTaskGroups = taskGroups;
+            mPendingAnimation.addEndListener(success -> applyLoadPlan(finalTaskGroups));
             return;
         }
 
@@ -1824,12 +1847,15 @@
 
         // Reset the focused task to avoiding initializing TaskViews layout as focused task during
         // binding. The focused task view will be updated after all the TaskViews are bound.
-        mFocusedTaskViewId = INVALID_TASK_ID;
+        setFocusedTaskViewId(INVALID_TASK_ID);
 
         // Removing views sets the currentPage to 0, so we save this and restore it after
         // the new set of views are added
         int previousCurrentPage = mCurrentPage;
         int previousFocusedPage = indexOfChild(getFocusedChild());
+        // TaskIds will no longer be valid after remove and re-add, clearing mTopRowIdSet.
+        mAnyTaskHasBeenDismissed = false;
+        mTopRowIdSet.clear();
         removeAllViews();
 
         // If we are entering Overview as a result of initiating a split from somewhere else
@@ -1847,6 +1873,11 @@
         // Clear out desktop view if it is set
         mDesktopTaskView = null;
 
+        // Move Desktop Tasks to the end of the list
+        if (enableLargeDesktopWindowingTile()) {
+            taskGroups = mUtils.sortDesktopTasksToFront(taskGroups);
+        }
+
         // Add views as children based on whether it's grouped or single task. Looping through
         // taskGroups backwards populates the thumbnail grid from least recent to most recent.
         for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -1900,11 +1931,14 @@
         // Keep same previous focused task
         TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
         // If the list changed, maybe the focused task doesn't exist anymore
-        if (newFocusedTaskView == null && getTaskViewCount() > 0) {
-            newFocusedTaskView = getTaskViewAt(0);
+        int newFocusedTaskViewIndex = mUtils.getFocusedTaskIndex(taskGroups);
+        if (newFocusedTaskView == null && getTaskViewCount() > newFocusedTaskViewIndex) {
+            newFocusedTaskView = getTaskViewAt(newFocusedTaskViewIndex);
         }
-        mFocusedTaskViewId = newFocusedTaskView != null && !enableGridOnlyOverview()
-                ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
+
+        setFocusedTaskViewId(newFocusedTaskView != null && !enableGridOnlyOverview()
+                ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID);
+
         updateTaskSize();
         updateChildTaskOrientations();
 
@@ -1944,8 +1978,8 @@
             // Set the current page to the running task, but not if settling on new task.
             if (hasAllValidTaskIds(runningTaskIds)) {
                 targetPage = indexOfChild(newRunningTaskView);
-            } else if (getTaskViewCount() > 0) {
-                targetPage = indexOfChild(requireTaskViewAt(0));
+            } else if (getTaskViewCount() > newFocusedTaskViewIndex) {
+                targetPage = indexOfChild(requireTaskViewAt(newFocusedTaskViewIndex));
             }
         }
         if (targetPage != -1 && mCurrentPage != targetPage) {
@@ -1970,6 +2004,7 @@
             // generally map to the same task.
             mIgnoreResetTaskId = INVALID_TASK_ID;
         }
+
         resetTaskVisuals();
         onTaskStackUpdated();
         updateEnabledOverlays();
@@ -1987,15 +2022,13 @@
     }
 
     private void removeTasksViewsAndClearAllButton() {
-        // This handles an edge case where applyLoadPlan happens during a gesture when the
-        // only Task is one with excludeFromRecents, in which case we should not remove it.
-        final int stubRunningTaskIndex = isGestureActive() ? getRunningTaskIndex() : -1;
-
-        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
-            if (i == stubRunningTaskIndex) {
+        for (TaskView taskView : getTaskViews()) {
+            if (isGestureActive() && taskView.isRunningTask()) {
+                // This handles an edge case where applyLoadPlan happens during a gesture when the
+                // only Task is one with excludeFromRecents, in which case we should not remove it.
                 continue;
             }
-            removeView(requireTaskViewAt(i));
+            removeView(taskView);
         }
         if (getTaskViewCount() == 0 && indexOfChild(mClearAllButton) != -1) {
             removeView(mClearAllButton);
@@ -2010,14 +2043,13 @@
         return taskViewCount;
     }
 
-    public int getGroupedTaskViewCount() {
-        int groupViewCount = 0;
-        for (int i = 0; i < getChildCount(); i++) {
-            if (getChildAt(i) instanceof GroupedTaskView) {
-                groupViewCount++;
-            }
-        }
-        return groupViewCount;
+    /**
+     * Transverse RecentsView children to calculate the amount of DesktopTaskViews.
+     *
+     * @return Number of children that are instances of DesktopTaskView
+     */
+    private int getDesktopTaskViewCount() {
+        return mUtils.getDesktopTaskViewCount(getTaskViews());
     }
 
     /**
@@ -2040,8 +2072,7 @@
     }
 
     public void resetTaskVisuals() {
-        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             if (Arrays.stream(taskView.getTaskIds()).noneMatch(
                     taskId -> taskId == mIgnoreResetTaskId)) {
                 taskView.resetViewTransforms();
@@ -2084,9 +2115,8 @@
         if (enableRefactorTaskThumbnail()) {
             mRecentsViewModel.updateFullscreenProgress(mFullscreenProgress);
         }
-        int taskCount = getTaskViewCount();
-        for (int i = 0; i < taskCount; i++) {
-            requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.setFullscreenProgress(mFullscreenProgress);
         }
         mClearAllButton.setFullscreenProgress(fullscreenProgress);
 
@@ -2099,6 +2129,7 @@
         boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
                 && getWindowVisibility() == VISIBLE;
         if (handleTaskStackChanges != mHandleTaskStackChanges) {
+            Log.d(TAG, "updateTaskStackListenerState: " + handleTaskStackChanges);
             mHandleTaskStackChanges = handleTaskStackChanges;
             if (handleTaskStackChanges) {
                 reloadIfNeeded();
@@ -2231,8 +2262,7 @@
                     ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
                     : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
         }
-        for (int i = 0; i < taskCount; i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             taskView.updateTaskSize(mLastComputedTaskSize, mLastComputedGridTaskSize,
                     mLastComputedCarouselTaskSize);
             taskView.setNonGridTranslationX(accumulatedTranslationX);
@@ -2508,7 +2538,6 @@
         }
 
         if (enableRefactorTaskThumbnail()) {
-            // TODO(b/342560598): Listen in TaskRepository and reload.
             return;
         }
 
@@ -2549,7 +2578,7 @@
         mCurrentPageScrollDiff = 0;
         mIgnoreResetTaskId = -1;
         mTaskListChangeId = -1;
-        mFocusedTaskViewId = -1;
+        setFocusedTaskViewId(INVALID_TASK_ID);
         mAnyTaskHasBeenDismissed = false;
 
 
@@ -2621,14 +2650,17 @@
         return getTaskViewFromTaskViewId(mFocusedTaskViewId);
     }
 
+    private @Nullable TaskView getFirstLargeTaskView() {
+        return mUtils.getFirstLargeTaskView(getTaskViews());
+    }
+
     @Nullable
     private TaskView getTaskViewFromTaskViewId(int taskViewId) {
         if (taskViewId == -1) {
             return null;
         }
 
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             if (taskView.getTaskViewId() == taskViewId) {
                 return taskView;
             }
@@ -2689,9 +2721,12 @@
         if (!mModel.isTaskListValid(mTaskListChangeId)) {
             mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
                     .getFilter(mFilterState.getPackageNameToFilter()));
+            Log.d(TAG, "reloadIfNeeded - getTasks: " + mTaskListChangeId);
             if (enableRefactorTaskThumbnail()) {
                 mRecentsViewModel.refreshAllTaskData();
             }
+        } else {
+            Log.d(TAG, "reloadIfNeeded - task list still valid: " + mTaskListChangeId);
         }
     }
 
@@ -2714,10 +2749,17 @@
         showCurrentTask(mActiveGestureRunningTasks);
         setEnableFreeScroll(false);
         setEnableDrawingLiveTile(false);
-        setRunningTaskHidden(true);
+        setRunningTaskHidden(!shouldUpdateRunningTaskAlpha());
         setTaskIconScaledDown(true);
     }
 
+    /**
+     * Returns whether the running task's attach alpha should be updated during the attach animation
+     */
+    public boolean shouldUpdateRunningTaskAlpha() {
+        return enableDesktopTaskAlphaAnimation() && getRunningTaskView() instanceof DesktopTaskView;
+    }
+
     private boolean isGestureActive() {
         return mActiveGestureRunningTasks != null;
     }
@@ -2767,8 +2809,8 @@
     }
 
     private void updateChildTaskOrientations() {
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            requireTaskViewAt(i).setOrientationState(mOrientationState);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.setOrientationState(mOrientationState);
         }
         boolean shouldRotateMenuForFakeRotation =
                 !mOrientationState.isRecentsActivityRotationAllowed();
@@ -2882,6 +2924,7 @@
         if (runningTasks.length == 0) {
             return;
         }
+
         int runningTaskViewId = -1;
         boolean needGroupTaskView = runningTasks.length > 1;
         boolean needDesktopTask = hasDesktopTask(runningTasks);
@@ -2926,7 +2969,11 @@
 
         boolean runningTaskTileHidden = mRunningTaskTileHidden;
         setCurrentTask(runningTaskViewId);
-        mFocusedTaskViewId = enableGridOnlyOverview() ? INVALID_TASK_ID : runningTaskViewId;
+
+        boolean shouldFocusRunningTask = !(enableGridOnlyOverview()
+                || (enableLargeDesktopWindowingTile()
+                && getRunningTaskView() instanceof DesktopTaskView));
+        setFocusedTaskViewId(shouldFocusRunningTask ? runningTaskViewId : INVALID_TASK_ID);
         runOnPageScrollsInitialized(() -> setCurrentPage(getRunningTaskIndex()));
         setRunningTaskViewShowScreenshot(false);
         setRunningTaskHidden(runningTaskTileHidden);
@@ -2978,6 +3025,10 @@
         }
     }
 
+    private void setFocusedTaskViewId(int viewId) {
+        mFocusedTaskViewId = viewId;
+    }
+
     private int getTaskViewIdFromTaskId(int taskId) {
         TaskView taskView = getTaskViewByTaskId(taskId);
         return taskView != null ? taskView.getTaskViewId() : -1;
@@ -2989,20 +3040,26 @@
     public void setRunningTaskHidden(boolean isHidden) {
         mRunningTaskTileHidden = isHidden;
         TaskView runningTask = getRunningTaskView();
-        if (runningTask != null) {
-            runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
-            if (!isHidden) {
-                AccessibilityManagerCompat.sendCustomAccessibilityEvent(runningTask,
-                        AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
-            }
+        if (runningTask == null) {
+            return;
+        }
+        runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
+        if (!isHidden) {
+            AccessibilityManagerCompat.sendCustomAccessibilityEvent(
+                    runningTask, AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
         }
     }
 
     private void setRunningTaskViewShowScreenshot(boolean showScreenshot) {
+        setRunningTaskViewShowScreenshot(showScreenshot, /*updatedThumbnails=*/null);
+    }
+
+    private void setRunningTaskViewShowScreenshot(boolean showScreenshot,
+            @Nullable Map<Integer, ThumbnailData> updatedThumbnails) {
         mRunningTaskShowScreenshot = showScreenshot;
         TaskView runningTaskView = getRunningTaskView();
         if (runningTaskView != null) {
-            runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot);
+            runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot, updatedThumbnails);
         }
         if (enableRefactorTaskThumbnail()) {
             mRecentsViewModel.setRunningTaskShowScreenshot(showScreenshot);
@@ -3012,9 +3069,8 @@
     public void setTaskIconScaledDown(boolean isScaledDown) {
         if (mTaskIconScaledDown != isScaledDown) {
             mTaskIconScaledDown = isScaledDown;
-            int taskCount = getTaskViewCount();
-            for (int i = 0; i < taskCount; i++) {
-                requireTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+            for (TaskView taskView : getTaskViews()) {
+                taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
             }
         }
     }
@@ -3027,9 +3083,7 @@
 
     public void animateUpTaskIconScale() {
         mTaskIconScaledDown = false;
-        int taskCount = getTaskViewCount();
-        for (int i = 0; i < taskCount; i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             taskView.animateIconScaleAndDimIntoView();
         }
     }
@@ -3077,8 +3131,9 @@
         float[] gridTranslations = new float[taskCount];
 
         int focusedTaskIndex = Integer.MAX_VALUE;
+        Set<Integer> largeTasksIndices = new HashSet<>();
         int focusedTaskShift = 0;
-        int focusedTaskWidthAndSpacing = 0;
+        int largeTaskWidthAndSpacing = 0;
         int snappedTaskRowWidth = 0;
         int snappedPage = isKeyboardTaskFocusPending() ? mKeyboardTaskFocusIndex : getNextPage();
         TaskView snappedTaskView = getTaskViewAt(snappedPage);
@@ -3095,12 +3150,11 @@
             // Evenly distribute tasks between rows unless rearranging due to task dismissal, in
             // which case keep tasks in their respective rows. For the running task, don't join
             // the grid.
-            if (taskView.isFocusedTask()) {
+            boolean isLargeTile = taskView.isLargeTile();
+
+            if (isLargeTile) {
                 topRowWidth += taskWidthAndSpacing;
                 bottomRowWidth += taskWidthAndSpacing;
-
-                focusedTaskIndex = i;
-                focusedTaskWidthAndSpacing = taskWidthAndSpacing;
                 gridTranslations[i] += focusedTaskShift;
                 gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
 
@@ -3108,6 +3162,12 @@
                 taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
                         - taskView.getLayoutParams().height) / 2f);
 
+                if (taskView.getTaskViewId() == mFocusedTaskViewId) {
+                    focusedTaskIndex = i;
+                }
+                largeTasksIndices.add(i);
+                largeTaskWidthAndSpacing = taskWidthAndSpacing;
+
                 if (taskView == snappedTaskView) {
                     // If focused task is snapped, the row width is just task width and spacing.
                     snappedTaskRowWidth = taskWidthAndSpacing;
@@ -3116,7 +3176,7 @@
                 if (i > focusedTaskIndex) {
                     // For tasks after the focused task, shift by focused task's width and spacing.
                     gridTranslations[i] +=
-                            mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+                            mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
                 } else {
                     // For task before the focused task, accumulate the width and spacing to
                     // calculate the distance focused task need to shift.
@@ -3152,7 +3212,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex) {
+                        if (largeTasksIndices.contains(j)) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3171,7 +3231,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex) {
+                        if (largeTasksIndices.contains(j)) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3221,12 +3281,22 @@
         // accordingly. Update longRowWidth if ClearAllButton has been moved.
         float clearAllShortTotalWidthTranslation = 0;
         int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
-        if (longRowWidth < mLastComputedGridSize.width()) {
-            mClearAllShortTotalWidthTranslation =
-                    (mIsRtl
-                            ? mLastComputedTaskSize.right
-                            : deviceProfile.widthPx - mLastComputedTaskSize.left)
-                            - longRowWidth - deviceProfile.overviewGridSideMargin;
+
+        // If Recents contains only large task sizes, it should only consider 1 large size
+        // for ClearAllButton translation. The space at the left side of the large task will be
+        // empty and it should be move ClearAllButton further away as well.
+        // TODO(b/359573248): Validate the translation for ClearAllButton for grid only.
+        boolean hasOnlyLargeTasks = taskCount == largeTasksIndices.size();
+        if (enableLargeDesktopWindowingTile() && hasOnlyLargeTasks) {
+            longRowWidth = largeTaskWidthAndSpacing;
+        }
+
+        // If first task is not in the expected position (mLastComputedTaskSize) and being too close
+        // to ClearAllButton, then apply extra translation to ClearAllButton.
+        int firstTaskStart = mLastComputedGridSize.left + longRowWidth;
+        int expectedFirstTaskStart = mLastComputedTaskSize.right;
+        if (firstTaskStart < expectedFirstTaskStart) {
+            mClearAllShortTotalWidthTranslation = expectedFirstTaskStart - firstTaskStart;
             clearAllShortTotalWidthTranslation = mIsRtl
                     ? -mClearAllShortTotalWidthTranslation : mClearAllShortTotalWidthTranslation;
             if (snappedTaskRowWidth == longRowWidth) {
@@ -3241,10 +3311,10 @@
         float clearAllTotalTranslationX =
                 clearAllAccumulatedTranslation + clearAllShorterRowCompensation
                         + clearAllShortTotalWidthTranslation + snappedTaskNonGridScrollAdjustment;
-        if (focusedTaskIndex < taskCount) {
+        if (!largeTasksIndices.isEmpty()) {
             // Shift by focused task's width and spacing if a task is focused.
             clearAllTotalTranslationX +=
-                    mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+                    mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
         }
 
         // Make sure there are enough space between snapped page and ClearAllButton, for the case
@@ -3284,7 +3354,6 @@
         mClearAllButton.setGridScrollOffset(
                 mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
                         : mLastComputedTaskSize.right - mLastComputedGridSize.right);
-
         setGridProgress(mGridProgress);
     }
 
@@ -3292,11 +3361,11 @@
         if (taskView1 == null || taskView2 == null) {
             return false;
         }
-        int taskViewId1 = taskView1.getTaskViewId();
-        int taskViewId2 = taskView2.getTaskViewId();
-        if (taskViewId1 == mFocusedTaskViewId || taskViewId2 == mFocusedTaskViewId) {
+        if (taskView1.isLargeTile() || taskView2.isLargeTile()) {
             return false;
         }
+        int taskViewId1 = taskView1.getTaskViewId();
+        int taskViewId2 = taskView2.getTaskViewId();
         return (mTopRowIdSet.contains(taskViewId1) && mTopRowIdSet.contains(taskViewId2)) || (
                 !mTopRowIdSet.contains(taskViewId1) && !mTopRowIdSet.contains(taskViewId2));
     }
@@ -3309,9 +3378,8 @@
     private void setGridProgress(float gridProgress) {
         mGridProgress = gridProgress;
 
-        int taskCount = getTaskViewCount();
-        for (int i = 0; i < taskCount; i++) {
-            requireTaskViewAt(i).setGridProgress(gridProgress);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.setGridProgress(gridProgress);
         }
         mClearAllButton.setGridProgress(gridProgress);
     }
@@ -3321,14 +3389,10 @@
             mRecentsViewModel.updateThumbnailSplashProgress(taskThumbnailSplashAlpha);
             return;
         }
-        int taskCount = getTaskViewCount();
-        if (taskCount == 0) {
-            return;
-        }
 
         mTaskThumbnailSplashAlpha = taskThumbnailSplashAlpha;
-        for (int i = 0; i < taskCount; i++) {
-            requireTaskViewAt(i).setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha);
         }
     }
 
@@ -3549,11 +3613,10 @@
                     isStagingFocusedTask = true;
                 } else {
                     nextFocusedTaskFromTop =
-                            mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
+                            !mTopRowIdSet.isEmpty() && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
                     // Pick the next focused task from the preferred row.
-                    for (int i = 0; i < taskCount; i++) {
-                        TaskView taskView = requireTaskViewAt(i);
-                        if (taskView == dismissedTaskView) {
+                    for (TaskView taskView : getTaskViews()) {
+                        if (taskView == dismissedTaskView || taskView.isLargeTile()) {
                             continue;
                         }
                         boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
@@ -3680,8 +3743,7 @@
                         END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
                                 + (taskCount - 1) * halfAdditionalDismissTranslationOffset,
                         END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
-                for (int i = 0; i < taskCount; i++) {
-                    TaskView taskView = requireTaskViewAt(i);
+                for (TaskView taskView : getTaskViews()) {
                     anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff,
                             clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1));
                     dismissTranslationInterpolationEnd = Utilities.boundToRange(
@@ -4017,9 +4079,9 @@
                     } else {
                         // Update focus task and its size.
                         if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
-                            mFocusedTaskViewId = enableGridOnlyOverview()
+                            setFocusedTaskViewId(enableGridOnlyOverview()
                                     ? INVALID_TASK_ID
-                                    : finalNextFocusedTaskView.getTaskViewId();
+                                    : finalNextFocusedTaskView.getTaskViewId());
                             mTopRowIdSet.remove(mFocusedTaskViewId);
                             finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
                         }
@@ -4141,9 +4203,8 @@
             return new IntArray(0);
         }
         IntArray topArray = new IntArray(mTopRowIdSet.size());
-        int taskViewCount = getTaskViewCount();
-        for (int i = 0; i < taskViewCount; i++) {
-            int taskViewId = requireTaskViewAt(i).getTaskViewId();
+        for (TaskView taskView : getTaskViews()) {
+            int taskViewId = taskView.getTaskViewId();
             if (mTopRowIdSet.contains(taskViewId)) {
                 topArray.add(taskViewId);
             }
@@ -4160,10 +4221,9 @@
             return new IntArray(0);
         }
         IntArray bottomArray = new IntArray(bottomRowIdArraySize);
-        int taskViewCount = getTaskViewCount();
-        for (int i = 0; i < taskViewCount; i++) {
-            int taskViewId = requireTaskViewAt(i).getTaskViewId();
-            if (!mTopRowIdSet.contains(taskViewId) && taskViewId != mFocusedTaskViewId) {
+        for (TaskView taskView : getTaskViews()) {
+            int taskViewId = taskView.getTaskViewId();
+            if (!mTopRowIdSet.contains(taskViewId) && !taskView.isLargeTile()) {
                 bottomArray.add(taskViewId);
             }
         }
@@ -4221,9 +4281,8 @@
         }
         PendingAnimation anim = new PendingAnimation(duration);
 
-        int count = getTaskViewCount();
-        for (int i = 0; i < count; i++) {
-            addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
+        for (TaskView taskView : getTaskViews()) {
+            addDismissedTaskAnimations(taskView, duration, anim);
         }
 
         mPendingAnimation = anim;
@@ -4269,6 +4328,7 @@
         }
 
         // Init task grid nav helper with top/bottom id arrays.
+        // TODO(b/361070854): Add keyboard navigation for all large tiles.
         TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
                 getBottomRowIdArray(), mFocusedTaskViewId);
 
@@ -4301,8 +4361,10 @@
     private void dismissTask(int taskId) {
         TaskView taskView = getTaskViewByTaskId(taskId);
         if (taskView == null) {
+            Log.d(TAG, "dismissTask: " + taskId + ",  no associated TaskView");
             return;
         }
+        Log.d(TAG, "dismissTask: " + taskId);
         dismissTask(taskView, true /* animate */, false /* removeTask */);
     }
 
@@ -4387,12 +4449,11 @@
         mContentAlpha = alpha;
 
         TaskView runningTaskView = getRunningTaskView();
-        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
-            TaskView child = requireTaskViewAt(i);
-            if (runningTaskView != null && mRunningTaskTileHidden && child == runningTaskView) {
+        for (TaskView taskView : getTaskViews()) {
+            if (runningTaskView != null && mRunningTaskTileHidden && taskView == runningTaskView) {
                 continue;
             }
-            child.setStableAlpha(alpha);
+            taskView.setStableAlpha(alpha);
         }
         mClearAllButton.setContentAlpha(mContentAlpha);
         int alphaInt = Math.round(alpha * 255);
@@ -4501,6 +4562,13 @@
         return Objects.requireNonNull(getTaskViewAt(index));
     }
 
+    /**
+     * Returns the current list of [TaskView] children.
+     */
+    private List<TaskView> getTaskViews() {
+        return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt);
+    }
+
     public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
         mOnEmptyMessageUpdatedListener = listener;
     }
@@ -4597,9 +4665,10 @@
                 ? (runningTask == null ? INVALID_PAGE : indexOfChild(runningTask))
                 : mOffsetMidpointIndexOverride;
         int modalMidpoint = getCurrentPage();
-        boolean isModalGridWithoutFocusedTask =
-                showAsGrid && enableGridOnlyOverview() && mTaskModalness > 0;
-        if (isModalGridWithoutFocusedTask) {
+        boolean shouldCalculateOffsetForAllTasks = showAsGrid
+                && (enableGridOnlyOverview() || enableLargeDesktopWindowingTile())
+                && mTaskModalness > 0;
+        if (shouldCalculateOffsetForAllTasks) {
             modalMidpoint = indexOfChild(mSelectedTask);
         }
 
@@ -4638,7 +4707,7 @@
                     : i < midpoint
                             ? leftOffsetSize
                             : rightOffsetSize;
-            if (isModalGridWithoutFocusedTask) {
+            if (shouldCalculateOffsetForAllTasks) {
                 gridOffsetSize = getHorizontalOffsetSize(i, modalMidpoint, modalOffset);
                 gridOffsetSize = Math.abs(gridOffsetSize) * (i <= modalMidpoint ? 1 : -1);
             }
@@ -4647,8 +4716,11 @@
                     : showAsGrid
                             ? gridOffsetSize
                             : i < modalMidpoint ? modalLeftOffsetSize : modalRightOffsetSize;
-            float totalTranslationX = translation + modalTranslation;
             View child = getChildAt(i);
+            boolean skipTranslationOffset = enableDesktopTaskAlphaAnimation()
+                    && i == getRunningTaskIndex()
+                    && child instanceof DesktopTaskView;
+            float totalTranslationX = (skipTranslationOffset ? 0f : translation) + modalTranslation;
             FloatProperty translationPropertyX = child instanceof TaskView
                     ? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
                     : getPagedOrientationHandler().getPrimaryViewTranslate();
@@ -4801,9 +4873,9 @@
 
     protected void setTaskViewsResistanceTranslation(float translation) {
         mTaskViewsSecondaryTranslation = translation;
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView task = requireTaskViewAt(i);
-            task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY());
+        for (TaskView taskView : getTaskViews()) {
+            taskView.getTaskResistanceTranslationProperty().set(taskView,
+                    translation / getScaleY());
         }
         runActionOnRemoteHandles(
                 remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
@@ -4811,23 +4883,21 @@
     }
 
     private void updateTaskViewsSnapshotRadius() {
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            requireTaskViewAt(i).updateSnapshotRadius();
+        for (TaskView taskView : getTaskViews()) {
+            taskView.updateSnapshotRadius();
         }
     }
 
     protected void setTaskViewsPrimarySplitTranslation(float translation) {
         mTaskViewsPrimarySplitTranslation = translation;
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView task = requireTaskViewAt(i);
-            task.getPrimarySplitTranslationProperty().set(task, translation);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.getPrimarySplitTranslationProperty().set(taskView, translation);
         }
     }
 
     protected void setTaskViewsSecondarySplitTranslation(float translation) {
         mTaskViewsSecondarySplitTranslation = translation;
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             if (taskView == mSplitHiddenTaskView && !taskView.containsMultipleTasks()) {
                 continue;
             }
@@ -5244,10 +5314,7 @@
 
         float toScale = getMaxScaleForFullScreen();
         boolean showAsGrid = showAsGrid();
-        boolean zoomInTaskView = showAsGrid
-                ? ((taskView.isFocusedTask() && isTaskViewFullyVisible(taskView))
-                || taskView instanceof DesktopTaskView)
-                : taskIndex == centerTaskIndex;
+        boolean zoomInTaskView = showAsGrid ? taskView.isLargeTile() : taskIndex == centerTaskIndex;
         if (zoomInTaskView) {
             anim.play(ObjectAnimator.ofFloat(this, RECENTS_SCALE_PROPERTY, toScale));
             anim.play(ObjectAnimator.ofFloat(this, FULLSCREEN_PROGRESS, 1));
@@ -5403,7 +5470,7 @@
                     finishRecentsAnimation(false /* toRecents */, null);
                     onTaskLaunchAnimationEnd(true /* success */);
                 } else {
-                    taskView.launchTask(this::onTaskLaunchAnimationEnd);
+                    taskView.launchWithoutAnimation(this::onTaskLaunchAnimationEnd);
                 }
                 mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo())
                         .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
@@ -5728,8 +5795,8 @@
     }
 
     private int getFirstViewIndex() {
-        TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
-        return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
+        TaskView firstTaskView = mShowAsGridLastOnLayout ? getFirstLargeTaskView() : null;
+        return firstTaskView != null ? indexOfChild(firstTaskView) : 0;
     }
 
     private int getLastViewIndex() {
@@ -5747,7 +5814,7 @@
         }
 
         // Returns focus task if there are no grid tasks.
-        return indexOfChild(getFocusedTaskView());
+        return indexOfChild(getFirstLargeTaskView());
     }
 
     /**
@@ -5963,7 +6030,7 @@
     public boolean isOnGridBottomRow(TaskView taskView) {
         return showAsGrid()
                 && !mTopRowIdSet.contains(taskView.getTaskViewId())
-                && taskView.getTaskViewId() != mFocusedTaskViewId;
+                && !taskView.isLargeTile();
     }
 
     public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
@@ -5997,9 +6064,7 @@
 
     private void updateEnabledOverlays() {
         TaskView focusedTaskView = getFocusedTaskView();
-        int taskCount = getTaskViewCount();
-        for (int i = 0; i < taskCount; i++) {
-            TaskView taskView = requireTaskViewAt(i);
+        for (TaskView taskView : getTaskViews()) {
             if (taskView == focusedTaskView) {
                 continue;
             }
@@ -6073,20 +6138,12 @@
             return;
         }
 
+        Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView,
+                mRecentsAnimationController);
         if (enableRefactorTaskThumbnail()) {
-            mHelper.switchToScreenshot(taskView, mRecentsAnimationController, onFinishRunnable);
+            mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable);
         } else {
-            setRunningTaskViewShowScreenshot(true);
-            for (TaskContainer container : taskView.getTaskContainers()) {
-                ThumbnailData thumbnailData =
-                        mRecentsAnimationController.screenshotTask(container.getTask().key.id);
-                TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailViewDeprecated();
-                if (thumbnailData != null) {
-                    thumbnailView.setThumbnail(container.getTask(), thumbnailData);
-                } else {
-                    thumbnailView.refresh();
-                }
-            }
+            setRunningTaskViewShowScreenshot(true, updatedThumbnails);
             ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
         }
     }
@@ -6105,8 +6162,7 @@
             if (enableRefactorTaskThumbnail()) {
                 mHelper.switchToScreenshot(taskView, thumbnailDatas, onFinishRunnable);
             } else {
-                taskView.setShouldShowScreenshot(true);
-                taskView.refreshThumbnails(thumbnailDatas);
+                taskView.setShouldShowScreenshot(true, thumbnailDatas);
                 ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
             }
         } else {
@@ -6180,8 +6236,8 @@
             mRecentsViewModel.setTintAmount(tintAmount);
         }
 
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
+        for (TaskView taskView : getTaskViews()) {
+            taskView.setColorTint(mColorTint, mTintingColor);
         }
 
         Drawable scrimBg = mContainer.getScrimView().getBackground();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
similarity index 70%
rename from quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
rename to quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index e8c9718..4604b70 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -16,7 +16,6 @@
 
 package com.android.quickstep.views
 
-import com.android.quickstep.RecentsAnimationController
 import com.android.quickstep.ViewUtils
 import com.android.quickstep.recents.viewmodel.RecentsViewModel
 import com.android.systemui.shared.recents.model.ThumbnailData
@@ -27,8 +26,8 @@
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
 
-/** Helper for [RecentsView] to interact with coroutine. */
-class RecentsViewHelper(private val recentsViewModel: RecentsViewModel) {
+/** Helper for [RecentsView] to interact with the [RecentsViewModel]. */
+class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) {
     private lateinit var viewAttachedScope: CoroutineScope
 
     fun onAttachedToWindow() {
@@ -42,20 +41,8 @@
 
     fun switchToScreenshot(
         taskView: TaskView,
-        recentsAnimationController: RecentsAnimationController,
-        onFinishRunnable: Runnable
-    ) {
-        val updatedThumbnails =
-            taskView.taskContainers.associate {
-                it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
-            }
-        switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable)
-    }
-
-    fun switchToScreenshot(
-        taskView: TaskView,
         updatedThumbnails: Map<Int, ThumbnailData>?,
-        onFinishRunnable: Runnable
+        onFinishRunnable: Runnable,
     ) {
         // Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
         // viewAttachedScope.
@@ -68,8 +55,4 @@
             ViewUtils.postFrameDrawn(taskView, onFinishRunnable)
         }
     }
-
-    fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData) {
-        recentsViewModel.addOrUpdateThumbnailOverride(mapOf(taskId to thumbnailData))
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index af32ba2..13c4f78 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -146,6 +146,7 @@
             }
 
     fun bind() {
+        digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
         if (enableRefactorTaskThumbnail()) {
             bindThumbnailView()
         } else {
@@ -171,4 +172,19 @@
             thumbnailViewDeprecated.setOverlayEnabled(enabled)
         }
     }
+
+    fun addChildForAccessibility(outChildren: ArrayList<View>) {
+        addAccessibleChildToList(iconView.asView(), outChildren)
+        addAccessibleChildToList(snapshotView, outChildren)
+        showWindowsView?.let { addAccessibleChildToList(it, outChildren) }
+        digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) }
+    }
+
+    private fun addAccessibleChildToList(view: View, outChildren: ArrayList<View>) {
+        if (view.includeForAccessibility()) {
+            outChildren.add(view)
+        } else {
+            view.addChildrenForAccessibility(outChildren)
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 158ae33..19d706f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -99,7 +99,7 @@
     private var optionMeasuredHeight = 0
     private val arrowHorizontalPadding: Int
         get() =
-            if (taskView.isFocusedTask)
+            if (taskView.isLargeTile)
                 resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
             else 0
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 176a538..601dae8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -49,6 +49,7 @@
 import com.android.launcher3.Flags.enableFocusOutline
 import com.android.launcher3.Flags.enableGridOnlyOverview
 import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview
+import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
 import com.android.launcher3.Flags.enableOverviewIconMenu
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.R
@@ -64,6 +65,7 @@
 import com.android.launcher3.util.Executors
 import com.android.launcher3.util.MultiPropertyFactory
 import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
+import com.android.launcher3.util.MultiValueAlpha
 import com.android.launcher3.util.RunnableList
 import com.android.launcher3.util.SafeCloseable
 import com.android.launcher3.util.SplitConfigurationOptions
@@ -77,7 +79,6 @@
 import com.android.launcher3.views.ActivityContext
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.RemoteAnimationTargets
-import com.android.quickstep.TaskAnimationManager
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.TaskViewUtils
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler
@@ -108,7 +109,7 @@
     defStyleRes: Int = 0,
     focusBorderAnimator: BorderAnimator? = null,
     hoverBorderAnimator: BorderAnimator? = null,
-    type: TaskViewType = TaskViewType.SINGLE
+    private val type: TaskViewType = TaskViewType.SINGLE,
 ) : FrameLayout(context, attrs), ViewPool.Reusable {
     /**
      * Used in conjunction with [onTaskListVisibilityChanged], providing more granularity on which
@@ -133,13 +134,15 @@
 
     val isGridTask: Boolean
         /** Returns whether the task is part of overview grid and not being focused. */
-        get() = container.deviceProfile.isTablet && !isFocusedTask
+        get() = container.deviceProfile.isTablet && !isLargeTile
 
     val isRunningTask: Boolean
         get() = this === recentsView?.runningTaskView
 
-    val isFocusedTask: Boolean
-        get() = this === recentsView?.focusedTaskView
+    val isLargeTile: Boolean
+        get() =
+            this == recentsView?.focusedTaskView ||
+                (enableLargeDesktopWindowingTile() && type == TaskViewType.DESKTOP)
 
     val taskCornerRadius: Float
         get() = currentFullscreenParams.cornerRadius
@@ -290,9 +293,6 @@
         set(value) {
             field = value
             applyScale()
-            if (enableRefactorTaskThumbnail()) {
-                taskViewModel.updateNonGridScale(value)
-            }
         }
 
     private var dismissScale = 1f
@@ -391,14 +391,23 @@
             applyTranslationX()
         }
 
-    protected var stableAlpha = 1f
+    private val taskViewAlpha = MultiValueAlpha(this, NUM_ALPHA_CHANNELS)
+
+    protected var stableAlpha
         set(value) {
-            field = value
-            alpha = stableAlpha
+            taskViewAlpha.get(ALPHA_INDEX_STABLE).value = value
         }
+        get() = taskViewAlpha.get(ALPHA_INDEX_STABLE).value
+
+    protected var attachAlpha
+        set(value) {
+            taskViewAlpha.get(ALPHA_INDEX_ATTACH).value = value
+        }
+        get() = taskViewAlpha.get(ALPHA_INDEX_ATTACH).value
 
     protected var shouldShowScreenshot = false
         get() = !isRunningTask || field
+        private set
 
     /** Enable or disable showing border on hover and focus change */
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -521,7 +530,7 @@
     public override fun onFocusChanged(
         gainFocus: Boolean,
         direction: Int,
-        previouslyFocusedRect: Rect?
+        previouslyFocusedRect: Rect?,
     ) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
         if (borderEnabled) {
@@ -682,7 +691,7 @@
     open fun bind(
         task: Task,
         orientedState: RecentsOrientedState,
-        taskOverlayFactory: TaskOverlayFactory
+        taskOverlayFactory: TaskOverlayFactory,
     ) {
 
         cancelPendingLoadTasks()
@@ -693,6 +702,7 @@
                     R.id.snapshot,
                     R.id.icon,
                     R.id.show_windows,
+                    R.id.digital_wellbeing_toast,
                     STAGE_POSITION_UNDEFINED,
                     taskOverlayFactory
                 )
@@ -706,8 +716,9 @@
         @IdRes thumbnailViewId: Int,
         @IdRes iconViewId: Int,
         @IdRes showWindowViewId: Int,
+        @IdRes digitalWellbeingBannerId: Int,
         @StagePosition stagePosition: Int,
-        taskOverlayFactory: TaskOverlayFactory
+        taskOverlayFactory: TaskOverlayFactory,
     ): TaskContainer {
         val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = findViewById(thumbnailViewId)!!
         val snapshotView =
@@ -721,6 +732,7 @@
                 thumbnailViewDeprecated
             }
         val iconView = getOrInflateIconView(iconViewId)
+        val digitalWellBeingToast = findViewById<DigitalWellBeingToast>(digitalWellbeingBannerId)!!
         return TaskContainer(
             this,
             task,
@@ -728,7 +740,7 @@
             iconView,
             TransformingTouchDelegate(iconView.asView()),
             stagePosition,
-            DigitalWellBeingToast(container, this),
+            digitalWellBeingToast,
             findViewById(showWindowViewId)!!,
             taskOverlayFactory
         )
@@ -766,7 +778,7 @@
     protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) {
         taskContainers.forEach {
             it.overlay.updateOrientationState(orientationState)
-            it.digitalWellBeingToast?.initialize(it.task)
+            it.digitalWellBeingToast?.initialize()
         }
     }
 
@@ -774,10 +786,10 @@
      * Updates TaskView scaling and translation required to support variable width if enabled, while
      * ensuring TaskView fits into screen in fullscreen.
      */
-    fun updateTaskSize(
+    open fun updateTaskSize(
         lastComputedTaskSize: Rect,
         lastComputedGridTaskSize: Rect,
-        lastComputedCarouselTaskSize: Rect
+        lastComputedCarouselTaskSize: Rect,
     ) {
         val thumbnailPadding = container.deviceProfile.overviewTaskThumbnailTopMarginPx
         val taskWidth = lastComputedTaskSize.width()
@@ -789,9 +801,10 @@
         if (container.deviceProfile.isTablet) {
             val boxWidth: Int
             val boxHeight: Int
-            if (isFocusedTask) {
-                // Task will be focused and should use focused task size. Use focusTaskRatio
-                // that is associated with the original orientation of the focused task.
+
+            // Focused task and Desktop tasks should use focusTaskRatio that is associated
+            // with the original orientation of the focused task.
+            if (isLargeTile) {
                 boxWidth = taskWidth
                 boxHeight = taskHeight
             } else {
@@ -817,10 +830,8 @@
         } else {
             nonGridScale = 1f
             boxTranslationY = 0f
-            expectedWidth = if (enableOverviewIconMenu()) taskWidth else LayoutParams.MATCH_PARENT
-            expectedHeight =
-                if (enableOverviewIconMenu()) taskHeight + thumbnailPadding
-                else LayoutParams.MATCH_PARENT
+            expectedWidth = taskWidth
+            expectedHeight = taskHeight + thumbnailPadding
         }
         this.nonGridScale = nonGridScale
         this.boxTranslationY = boxTranslationY
@@ -837,6 +848,7 @@
         taskContainers[0].snapshotView.updateLayoutParams<LayoutParams> {
             topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
         }
+        taskContainers.forEach { it.digitalWellBeingToast?.setupLayout() }
     }
 
     /** Returns the thumbnail's bounds, optionally relative to the screen. */
@@ -929,7 +941,7 @@
         if (enableOverviewIconMenu()) {
             setText(taskContainer.iconView, taskContainer.task.title)
         }
-        taskContainer.digitalWellBeingToast?.initialize(taskContainer.task)
+        taskContainer.digitalWellBeingToast?.initialize()
     }
 
     protected open fun onIconUnloaded(taskContainer: TaskContainer) {
@@ -964,7 +976,13 @@
         iconView.setText(text)
     }
 
-    open fun refreshThumbnails(thumbnailDatas: Map<Int, ThumbnailData?>?) {
+    @JvmOverloads
+    open fun setShouldShowScreenshot(
+        shouldShowScreenshot: Boolean,
+        thumbnailDatas: Map<Int, ThumbnailData?>? = null
+    ) {
+        if (this.shouldShowScreenshot == shouldShowScreenshot) return
+        this.shouldShowScreenshot = shouldShowScreenshot
         if (enableRefactorTaskThumbnail()) {
             return
         }
@@ -985,7 +1003,7 @@
             return
         }
         val callbackList =
-            launchTasks()?.apply {
+            launchWithAnimation()?.apply {
                 add {
                     Log.d("b/310064698", "${taskIds.contentToString()} - onClick - launchCompleted")
                 }
@@ -997,12 +1015,106 @@
             .log(LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP)
     }
 
+    /** Launch of the current task (both live and inactive tasks) with an animation. */
+    fun launchWithAnimation(): RunnableList? {
+        return if (isRunningTask && recentsView?.remoteTargetHandles != null) {
+            launchAsLiveTile()
+        } else {
+            launchAsStaticTile()
+        }
+    }
+
+    private fun launchAsLiveTile(): RunnableList? {
+        val recentsView = recentsView ?: return null
+        val remoteTargetHandles = recentsView.remoteTargetHandles
+        if (!isClickableAsLiveTile) {
+            Log.e(
+                TAG,
+                "launchAsLiveTile - TaskView is not clickable as a live tile; returning to home: ${taskIds.contentToString()}"
+            )
+            return null
+        }
+        isClickableAsLiveTile = false
+        val targets =
+            if (remoteTargetHandles.size == 1) {
+                remoteTargetHandles[0].transformParams.targetSet
+            } else {
+                val apps =
+                    remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() }
+                val wallpapers =
+                    remoteTargetHandles.flatMap {
+                        it.transformParams.targetSet.wallpapers.asIterable()
+                    }
+                RemoteAnimationTargets(
+                    apps.toTypedArray(),
+                    wallpapers.toTypedArray(),
+                    remoteTargetHandles[0].transformParams.targetSet.nonApps,
+                    remoteTargetHandles[0].transformParams.targetSet.targetMode
+                )
+            }
+        if (targets == null) {
+            // If the recents animation is cancelled somehow between the parent if block and
+            // here, try to launch the task as a non live tile task.
+            val runnableList = launchAsStaticTile()
+            if (runnableList == null) {
+                Log.e(
+                    TAG,
+                    "launchAsLiveTile - Recents animation cancelled and cannot launch task as non-live tile; returning to home: ${taskIds.contentToString()}"
+                )
+            }
+            isClickableAsLiveTile = true
+            return runnableList
+        }
+        TestLogging.recordEvent(
+            TestProtocol.SEQUENCE_MAIN,
+            "composeRecentsLaunchAnimator",
+            taskIds.contentToString()
+        )
+        val runnableList = RunnableList()
+        with(AnimatorSet()) {
+            TaskViewUtils.composeRecentsLaunchAnimator(
+                this,
+                this@TaskView,
+                targets.apps,
+                targets.wallpapers,
+                targets.nonApps,
+                true /* launcherClosing */,
+                recentsView.stateManager,
+                recentsView,
+                recentsView.depthController
+            )
+            addListener(
+                object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animator: Animator) {
+                        if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) {
+                            launchAsStaticTile()
+                        }
+                        isClickableAsLiveTile = true
+                        runEndCallback()
+                    }
+
+                    override fun onAnimationCancel(animation: Animator) {
+                        runEndCallback()
+                    }
+
+                    private fun runEndCallback() {
+                        runnableList.executeAllAndDestroy()
+                    }
+                }
+            )
+            start()
+        }
+        Log.d(TAG, "launchAsLiveTile - composeRecentsLaunchAnimator: ${taskIds.contentToString()}")
+        recentsView.onTaskLaunchedInLiveTileMode()
+        return runnableList
+    }
+
     /**
      * Starts the task associated with this view and animates the startup.
      *
      * @return CompletionStage to indicate the animation completion or null if the launch failed.
      */
-    open fun launchTaskAnimated(): RunnableList? {
+    open fun launchAsStaticTile(): RunnableList? {
         TestLogging.recordEvent(
             TestProtocol.SEQUENCE_MAIN,
             "startActivityFromRecentsAsync",
@@ -1018,41 +1130,41 @@
         ) {
             Log.d(
                 TAG,
-                "launchTaskAnimated - startActivityFromRecents: ${taskIds.contentToString()}"
+                "launchAsStaticTile - startActivityFromRecents: ${taskIds.contentToString()}"
             )
             ActiveGestureLog.INSTANCE.trackEvent(
                 ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED
             )
             val recentsView = recentsView ?: return null
-            if (recentsView.runningTaskViewId != -1) {
+            if (
+                recentsView.runningTaskViewId != -1 &&
+                    recentsView.mRecentsAnimationController != null
+            ) {
                 recentsView.onTaskLaunchedInLiveTileMode()
 
                 // Return a fresh callback in the live tile case, so that it's not accidentally
                 // triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
                 return RunnableList().also { recentsView.addSideTaskLaunchCallback(it) }
             }
-            if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-                // If the recents transition is running (ie. in live tile mode), then the start
-                // of a new task will merge into the existing transition and it currently will
-                // not be run independently, so we need to rely on the onTaskAppeared() call
-                // for the new task to trigger the side launch callback to flush this runnable
-                // list (which is usually flushed when the app launch animation finishes)
-                recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
-            }
+            // If the recents transition is running (ie. in live tile mode), then the start
+            // of a new task will merge into the existing transition and it currently will
+            // not be run independently, so we need to rely on the onTaskAppeared() call
+            // for the new task to trigger the side launch callback to flush this runnable
+            // list (which is usually flushed when the app launch animation finishes)
+            recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
             return opts.onEndCallback
         } else {
-            notifyTaskLaunchFailed()
+            notifyTaskLaunchFailed("launchAsStaticTile")
             return null
         }
     }
 
     /** Starts the task associated with this view without any animation */
-    fun launchTask(callback: (launched: Boolean) -> Unit) {
-        launchTask(callback, isQuickSwitch = false)
-    }
-
-    /** Starts the task associated with this view without any animation */
-    open fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
+    @JvmOverloads
+    open fun launchWithoutAnimation(
+        isQuickSwitch: Boolean = false,
+        callback: (launched: Boolean) -> Unit
+    ) {
         TestLogging.recordEvent(
             TestProtocol.SEQUENCE_MAIN,
             "startActivityFromRecentsAsync",
@@ -1065,7 +1177,7 @@
             // gesture launcher is in the background state, vs other launches which are in
             // the actual overview state
             failureListener.register(container, firstContainer.task.key.id) {
-                notifyTaskLaunchFailed()
+                notifyTaskLaunchFailed("launchWithoutAnimation")
                 recentsView?.let {
                     // Disable animations for now, as it is an edge case and the app usually
                     // covers launcher and also any state transition animation also gets
@@ -1109,103 +1221,20 @@
                 // otherwise, wait for the animation start callback from the activity options
                 // above
                 Executors.MAIN_EXECUTOR.post {
-                    notifyTaskLaunchFailed()
+                    notifyTaskLaunchFailed("launchTask")
                     callback(false)
                 }
             }
-            Log.d(TAG, "launchTask - startActivityFromRecents: ${taskIds.contentToString()}")
+            Log.d(
+                TAG,
+                "launchWithoutAnimation - startActivityFromRecents: ${taskIds.contentToString()}"
+            )
         }
     }
 
-    /** Launch of the current task (both live and inactive tasks) with an animation. */
-    fun launchTasks(): RunnableList? {
-        val recentsView = recentsView ?: return null
-        val remoteTargetHandles = recentsView.mRemoteTargetHandles
-        if (!isRunningTask || remoteTargetHandles == null) {
-            return launchTaskAnimated()
-        }
-        if (!isClickableAsLiveTile) {
-            Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.")
-            return null
-        }
-        isClickableAsLiveTile = false
-        val targets =
-            if (remoteTargetHandles.size == 1) {
-                remoteTargetHandles[0].transformParams.targetSet
-            } else {
-                val apps =
-                    remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() }
-                val wallpapers =
-                    remoteTargetHandles.flatMap {
-                        it.transformParams.targetSet.wallpapers.asIterable()
-                    }
-                RemoteAnimationTargets(
-                    apps.toTypedArray(),
-                    wallpapers.toTypedArray(),
-                    remoteTargetHandles[0].transformParams.targetSet.nonApps,
-                    remoteTargetHandles[0].transformParams.targetSet.targetMode
-                )
-            }
-        if (targets == null) {
-            // If the recents animation is cancelled somehow between the parent if block and
-            // here, try to launch the task as a non live tile task.
-            val runnableList = launchTaskAnimated()
-            if (runnableList == null) {
-                Log.e(
-                    TAG,
-                    "Recents animation cancelled and cannot launch task as non-live tile" +
-                        "; returning to home"
-                )
-            }
-            isClickableAsLiveTile = true
-            return runnableList
-        }
-        TestLogging.recordEvent(
-            TestProtocol.SEQUENCE_MAIN,
-            "composeRecentsLaunchAnimator",
-            taskIds.contentToString()
-        )
-        val runnableList = RunnableList()
-        with(AnimatorSet()) {
-            TaskViewUtils.composeRecentsLaunchAnimator(
-                this,
-                this@TaskView,
-                targets.apps,
-                targets.wallpapers,
-                targets.nonApps,
-                true /* launcherClosing */,
-                recentsView.stateManager,
-                recentsView,
-                recentsView.depthController
-            )
-            addListener(
-                object : AnimatorListenerAdapter() {
-                    override fun onAnimationEnd(animator: Animator) {
-                        if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) {
-                            launchTaskAnimated()
-                        }
-                        isClickableAsLiveTile = true
-                        runEndCallback()
-                    }
-
-                    override fun onAnimationCancel(animation: Animator) {
-                        runEndCallback()
-                    }
-
-                    private fun runEndCallback() {
-                        runnableList.executeAllAndDestroy()
-                    }
-                }
-            )
-            start()
-        }
-        Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: ${taskIds.contentToString()}")
-        recentsView.onTaskLaunchedInLiveTileMode()
-        return runnableList
-    }
-
-    private fun notifyTaskLaunchFailed() {
-        val sb = StringBuilder("Failed to launch task \n")
+    private fun notifyTaskLaunchFailed(launchMethod: String) {
+        val sb =
+            StringBuilder("$launchMethod - Failed to launch task: ${taskIds.contentToString()}\n")
         taskContainers.forEach {
             sb.append("(task=${it.task.key.baseIntent} userId=${it.task.key.userId})\n")
         }
@@ -1334,7 +1363,7 @@
     private fun computeAndSetIconTouchDelegate(
         view: TaskViewIcon,
         tempCenterCoordinates: FloatArray,
-        transformingTouchDelegate: TransformingTouchDelegate
+        transformingTouchDelegate: TransformingTouchDelegate,
     ) {
         val viewHalfWidth = view.width / 2f
         val viewHalfHeight = view.height / 2f
@@ -1397,7 +1426,7 @@
     private fun onFocusTransitionProgressUpdated(focusTransitionProgress: Float) {
         taskContainers.forEach {
             it.iconView.setContentAlpha(focusTransitionProgress)
-            it.digitalWellBeingToast?.updateBannerOffset(1f - focusTransitionProgress)
+            it.digitalWellBeingToast?.bannerOffsetPercentage = 1f - focusTransitionProgress
         }
     }
 
@@ -1430,7 +1459,7 @@
                 it.thumbnailViewDeprecated.dimAlpha = amount
             }
             it.iconView.setIconColorTint(tintColor, amount)
-            it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount)
+            it.digitalWellBeingToast?.setColorTint(tintColor, amount)
         }
     }
 
@@ -1444,7 +1473,7 @@
         taskContainers.forEach {
             if (visibility == VISIBLE || it.task.key.id == taskId) {
                 it.snapshotView.visibility = visibility
-                it.digitalWellBeingToast?.setBannerVisibility(visibility)
+                it.digitalWellBeingToast?.visibility = visibility
                 it.showWindowsView?.visibility = visibility
                 it.overlay.setVisibility(visibility)
             }
@@ -1547,7 +1576,7 @@
     private fun onModalnessUpdated(modalness: Float) {
         taskContainers.forEach {
             it.iconView.setModalAlpha(1 - modalness)
-            it.digitalWellBeingToast?.updateBannerOffset(modalness)
+            it.digitalWellBeingToast?.bannerOffsetPercentage = modalness
         }
     }
 
@@ -1583,7 +1612,7 @@
         }
         dismissScale = 1f
         translationZ = 0f
-        alpha = stableAlpha
+        attachAlpha = 1f
         setIconScaleAndDim(1f)
         setColorTint(0f, 0)
     }
@@ -1648,6 +1677,12 @@
         return thumbnailBounds.contains(x.toInt(), y.toInt())
     }
 
+    override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
+        (if (isLayoutRtl) taskContainers.reversed() else taskContainers).forEach {
+            it.addChildForAccessibility(outChildren)
+        }
+    }
+
     companion object {
         private const val TAG = "TaskView"
         const val FLAG_UPDATE_ICON = 1
@@ -1660,6 +1695,11 @@
         const val FOCUS_TRANSITION_INDEX_SCALE_AND_DIM = 1
         const val FOCUS_TRANSITION_INDEX_COUNT = 2
 
+        private const val ALPHA_INDEX_STABLE = 0
+        private const val ALPHA_INDEX_ATTACH = 1
+
+        private const val NUM_ALPHA_CHANNELS = 2
+
         /** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
         const val MAX_PAGE_SCRIM_ALPHA = 0.4f
         const val SCALE_ICON_DURATION: Long = 120
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
index d77ac5c..eb459ff 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
@@ -25,7 +25,7 @@
 import android.view.LayoutInflater
 import androidx.test.core.app.ApplicationProvider
 import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
 import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
 import org.junit.Rule
 import org.junit.Test
@@ -99,7 +99,7 @@
         val flags =
             if (suppressNotification) Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION else 0
         val bubbleInfo =
-            BubbleInfo("key", flags, null, null, 0, context.packageName, null, null, false)
+            BubbleInfo("key", flags, null, null, 0, context.packageName, null, null, false, true)
         val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null) as BubbleView
         val dotPath =
             PathParser.createPathFromPathData(
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
new file mode 100644
index 0000000..72bbfc9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.taskbar
+
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+class TaskbarDesktopModeControllerTest {
+
+    private val context =
+        TaskbarWindowSandboxContext.create(
+            InstrumentationRegistry.getInstrumentation().targetContext
+        )
+
+    @get:Rule(order = 0) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+    @TaskbarUnitTestRule.InjectController
+    lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
+
+    @Test
+    fun whenTaskbarRequiresCornerRoundness_shouldReturnDefaultCornerRoundness() {
+        assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(true))
+            .isEqualTo(MAX_ROUNDNESS)
+    }
+
+    @Test
+    fun whenTaskbarRequiresCornerRoundness_shouldReturnZeroAsCornerRoundness() {
+        assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(false)).isEqualTo(0f)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt
new file mode 100644
index 0000000..4aac1dc
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2024 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.taskbar
+
+import android.view.View
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.TaskbarViewController.DIVIDER_VIEW_POSITION_OFFSET
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+/**
+ * Legend for the comments below:
+ * A: All Apps Button
+ * H: Hotseat item
+ * |: Divider
+ * R: Recent item
+ *
+ * The comments are formatted in two lines:
+ * // Items in taskbar, e.g.               A  |  HHHHHH
+ * // Index of items relative to Hotseat: -1 -.5 012345
+ */
+class TaskbarViewControllerTest {
+
+    private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+    @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+    @InjectController lateinit var taskbarViewController: TaskbarViewController
+
+    @Test
+    fun testGetPositionInHotseat_allAppsButton_nonRtl() {
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ 6,
+                /* child = */ View(context),
+                /* isRtl = */ false,
+                /* isAllAppsButton = */ true,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ -1
+            )
+        // [>A<] | [HHHHHH]
+        //  -1 -.5  012345
+        assertThat(position).isEqualTo(-1)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_allAppsButton_rtl() {
+        val numShownHotseatIcons = 6
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ true,
+                /* isAllAppsButton = */ true,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ -1
+            )
+        // [HHHHHH] | [>A<]
+        //  012345 5.5  6
+        assertThat(position).isEqualTo(numShownHotseatIcons)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_dividerView_notForRecents_nonRtl() {
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ 6,
+                /* child = */ View(context),
+                /* isRtl = */ false,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ true,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ -1
+            )
+        // [A] >|< [HHHHHH]
+        // -1  -.5  012345
+        assertThat(position).isEqualTo(-DIVIDER_VIEW_POSITION_OFFSET)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_dividerView_forRecents_nonRtl() {
+        val numShownHotseatIcons = 6
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ false,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ true,
+                /* isDividerForRecents = */ true,
+                /* recentTaskIndex = */ -1
+            )
+        // [A] [HHHHHH] >|< [RR]
+        // -1   012345  5.5  67
+        assertThat(position).isEqualTo(numShownHotseatIcons - DIVIDER_VIEW_POSITION_OFFSET)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_dividerView_notForRecents_rtl() {
+        val numShownHotseatIcons = 6
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ true,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ true,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ -1
+            )
+        // [HHHHHH] >|< [A]
+        //  012345  5.5  6
+        assertThat(position).isEqualTo(numShownHotseatIcons - DIVIDER_VIEW_POSITION_OFFSET)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_dividerView_forRecents_rtl() {
+        val numShownHotseatIcons = 6
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ true,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ true,
+                /* isDividerForRecents = */ true,
+                /* recentTaskIndex = */ -1
+            )
+        // [HHHHHH][A] >|< [RR]
+        //  012345  6  6.5  78
+        assertThat(position).isEqualTo(numShownHotseatIcons + DIVIDER_VIEW_POSITION_OFFSET)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_recentTasks_firstRecentIndex_nonRtl() {
+        val numShownHotseatIcons = 6
+        val recentTaskIndex = 0
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ false,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ recentTaskIndex
+            )
+        // [A][HHHHHH] | [>R<R]
+        // -1  012345 5.5  6 7
+        assertThat(position).isEqualTo(numShownHotseatIcons + recentTaskIndex)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_recentTasks_secondRecentIndex_nonRtl() {
+        val numShownHotseatIcons = 6
+        val recentTaskIndex = 1
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ false,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ recentTaskIndex
+            )
+        // [A][HHHHHH] | [R>R<]
+        // -1  012345 5.5 6 7
+        assertThat(position).isEqualTo(numShownHotseatIcons + recentTaskIndex)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_recentTasks_firstRecentIndex_rtl() {
+        val numShownHotseatIcons = 6
+        val recentTaskIndex = 0
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ true,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ recentTaskIndex
+            )
+        // [HHHHHH][A] | [>R<R]
+        //  012345  6 6.5  7 8
+        assertThat(position).isEqualTo(numShownHotseatIcons + 1 + recentTaskIndex)
+    }
+
+    @Test
+    fun testGetPositionInHotseat_recentTasks_secondRecentIndex_rtl() {
+        val numShownHotseatIcons = 6
+        val recentTaskIndex = 1
+        val position =
+            taskbarViewController.getPositionInHotseat(
+                /* numShownHotseatIcons = */ numShownHotseatIcons,
+                /* child = */ View(context),
+                /* isRtl = */ true,
+                /* isAllAppsButton = */ false,
+                /* isTaskbarDividerView = */ false,
+                /* isDividerForRecents = */ false,
+                /* recentTaskIndex = */ recentTaskIndex
+            )
+        // [HHHHHH][A] | [R>R<]
+        //  012345  6 6.5 7 8
+        assertThat(position).isEqualTo(numShownHotseatIcons + 1 + recentTaskIndex)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
new file mode 100644
index 0000000..785ec66
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 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.taskbar.bubbles
+
+import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for bubble bar input consumer, namely the static method that indicates whether the input
+ * consumer should handle the event.
+ */
+@RunWith(AndroidJUnit4::class)
+class BubbleBarInputConsumerTest {
+
+    private lateinit var bubbleControllers: BubbleControllers
+
+    @Mock private lateinit var taskbarActivityContext: TaskbarActivityContext
+    @Mock private lateinit var bubbleBarController: BubbleBarController
+    @Mock private lateinit var bubbleBarViewController: BubbleBarViewController
+    @Mock private lateinit var bubbleStashController: BubbleStashController
+    @Mock private lateinit var bubbleStashedHandleViewController: BubbleStashedHandleViewController
+    @Mock private lateinit var bubbleDragController: BubbleDragController
+    @Mock private lateinit var bubbleDismissController: BubbleDismissController
+    @Mock private lateinit var bubbleBarPinController: BubbleBarPinController
+    @Mock private lateinit var bubblePinController: BubblePinController
+    @Mock private lateinit var bubbleCreator: BubbleCreator
+
+    @Mock private lateinit var motionEvent: MotionEvent
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        bubbleControllers =
+            BubbleControllers(
+                bubbleBarController,
+                bubbleBarViewController,
+                bubbleStashController,
+                Optional.of(bubbleStashedHandleViewController),
+                bubbleDragController,
+                bubbleDismissController,
+                bubbleBarPinController,
+                bubblePinController,
+                bubbleCreator
+            )
+    }
+
+    @Test
+    fun testIsEventOnBubbles_noTaskbarActivityContext() {
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(null, motionEvent)).isFalse()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_bubblesNotEnabled() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(false)
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isFalse()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_noBubbleControllers() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(null)
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isFalse()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_noBubbles() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+        whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isFalse()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_eventOnStashedHandle() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+        whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+        whenever(bubbleStashController.isStashed).thenReturn(true)
+        whenever(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(true)
+
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isTrue()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_eventNotOnStashedHandle() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+        whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+        whenever(bubbleStashController.isStashed).thenReturn(true)
+        whenever(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(false)
+
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isFalse()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_eventOnVisibleBubbleView() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+        whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+        whenever(bubbleStashController.isStashed).thenReturn(false)
+        whenever(bubbleBarViewController.isBubbleBarVisible).thenReturn(true)
+        whenever(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(true)
+
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isTrue()
+    }
+
+    @Test
+    fun testIsEventOnBubbles_eventNotOnVisibleBubbleView() {
+        whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+        whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+        whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+        whenever(bubbleStashController.isStashed).thenReturn(false)
+        whenever(bubbleBarViewController.isBubbleBarVisible).thenReturn(true)
+        whenever(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(false)
+
+        assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+            .isFalse()
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
index 8bad3b9..94f9cf5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
@@ -27,7 +27,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -65,7 +65,7 @@
             overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
 
             val bubbleInfo =
-                BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+                BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
             bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null, false) as BubbleView
             bubble =
                 BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "")
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 4da06e1..84e872d 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -37,9 +37,9 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BubbleInfo
 import com.android.wm.shell.shared.animation.PhysicsAnimator
 import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
+import com.android.wm.shell.shared.bubbles.BubbleInfo
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
@@ -64,6 +64,7 @@
     private lateinit var bubble: BubbleBarBubble
     private lateinit var bubbleBarView: BubbleBarView
     private lateinit var bubbleStashController: BubbleStashController
+    private val onExpandedNoOp = Runnable {}
 
     @Before
     fun setUp() {
@@ -81,7 +82,12 @@
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -125,7 +131,12 @@
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -168,7 +179,12 @@
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -208,7 +224,12 @@
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -249,7 +270,12 @@
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -278,8 +304,15 @@
         val handleAnimator = PhysicsAnimator.getInstance(handle)
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = true)
@@ -303,6 +336,7 @@
         assertThat(animatorScheduler.delayedBlock).isNull()
 
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -314,8 +348,15 @@
         val handleAnimator = PhysicsAnimator.getInstance(handle)
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -345,6 +386,7 @@
             .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isFalse()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -356,8 +398,15 @@
         val handleAnimator = PhysicsAnimator.getInstance(handle)
         whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -384,6 +433,7 @@
             .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isFalse()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -400,7 +450,12 @@
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
@@ -442,8 +497,15 @@
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
@@ -459,6 +521,7 @@
 
         assertThat(animatorScheduler.delayedBlock).isNull()
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -471,7 +534,12 @@
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -502,8 +570,15 @@
         whenever(bubbleStashController.bubbleBarTranslationY)
             .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -533,6 +608,7 @@
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -542,8 +618,15 @@
         whenever(bubbleStashController.bubbleBarTranslationY)
             .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -566,6 +649,7 @@
 
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(animator.isAnimating).isFalse()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -578,7 +662,12 @@
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpandedNoOp,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -617,8 +706,15 @@
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleBarForCollapsed(bubble, isExpanding = true)
@@ -645,6 +741,7 @@
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(bubbleBarView.isExpanded).isTrue()
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -656,8 +753,15 @@
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -695,6 +799,7 @@
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(bubbleBarView.isExpanded).isTrue()
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     @Test
@@ -706,8 +811,15 @@
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
+        var notifiedExpanded = false
+        val onExpanded = Runnable { notifiedExpanded = true }
         val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+            BubbleBarViewAnimator(
+                bubbleBarView,
+                bubbleStashController,
+                onExpanded,
+                animatorScheduler
+            )
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -742,6 +854,7 @@
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(bubbleBarView.isExpanded).isTrue()
         verify(bubbleStashController).showBubbleBarImmediate()
+        assertThat(notifiedExpanded).isTrue()
     }
 
     private fun setUpBubbleBar() {
@@ -757,7 +870,7 @@
             bubbleBarView.addView(overflowView)
 
             val bubbleInfo =
-                BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+                BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
             bubbleView =
                 inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
             bubble =
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index c0a5dfa..4106a2c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -251,7 +251,7 @@
 
         whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
         whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(translationY)
-        whenever(bubbleBarViewController.bubbleBarScale).thenReturn(scale)
+        whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(scale)
         whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(alpha)
         whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
     }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index b5809c2..262d8da 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -31,7 +31,6 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
 import com.android.launcher3.util.MultiValueAlpha
 import com.android.wm.shell.shared.animation.PhysicsAnimator
 import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -55,11 +54,13 @@
 
     companion object {
         const val TASKBAR_BOTTOM_SPACE = 5
+        const val BUBBLE_BAR_WIDTH = 200f
         const val BUBBLE_BAR_HEIGHT = 100f
         const val HOTSEAT_TRANSLATION_Y = -45f
         const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
+        const val HANDLE_VIEW_WIDTH = 150
         const val HANDLE_VIEW_HEIGHT = 4
-        const val BUBBLE_BAR_STASHED_TRANSLATION_Y = 48
+        const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -2.5f
     }
 
     @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
@@ -76,7 +77,8 @@
     private lateinit var bubbleBarView: BubbleBarView
     private lateinit var stashedHandleView: StashedHandleView
     private lateinit var barTranslationY: AnimatedFloat
-    private lateinit var barScale: AnimatedFloat
+    private lateinit var barScaleX: AnimatedFloat
+    private lateinit var barScaleY: AnimatedFloat
     private lateinit var barAlpha: MultiValueAlpha
     private lateinit var stashedHandleAlpha: MultiValueAlpha
     private lateinit var stashedHandleScale: AnimatedFloat
@@ -90,7 +92,7 @@
         val taskbarHotseatDimensionsProvider =
             DefaultDimensionsProvider(taskBarBottomSpace = TASKBAR_BOTTOM_SPACE)
         mTransientBubbleStashController =
-            TransientBubbleStashController(taskbarHotseatDimensionsProvider, context.resources)
+            TransientBubbleStashController(taskbarHotseatDimensionsProvider, context)
         setUpBubbleBarView()
         setUpBubbleBarController()
         setUpStashedHandleView()
@@ -174,8 +176,8 @@
         assertThat(mTransientBubbleStashController.isStashed).isTrue()
         assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
         assertThat(bubbleBarView.alpha).isEqualTo(0f)
-        assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
-        assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+        assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+        assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
         // Handle view is visible
         assertThat(stashedHandleView.translationY).isEqualTo(0)
         assertThat(stashedHandleView.alpha).isEqualTo(1)
@@ -196,7 +198,7 @@
 
         // Then
         assertThat(barTranslationY.isAnimating).isTrue()
-        assertThat(barScale.isAnimating).isTrue()
+        assertThat(barScaleX.isAnimating).isTrue()
         // Wait until animation ends
         advanceTimeBy(BubbleStashController.BAR_STASH_DURATION)
 
@@ -243,8 +245,8 @@
         // Then all property values are updated
         assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
-        assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
-        assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+        assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+        assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
         // Handle is visible at correct Y position
         assertThat(stashedHandleView.alpha).isEqualTo(1)
         assertThat(stashedHandleView.translationY).isEqualTo(0)
@@ -294,20 +296,16 @@
     private fun setUpBubbleBarController() {
         barTranslationY =
             AnimatedFloat(Runnable { bubbleBarView.translationY = barTranslationY.value })
-        barScale =
-            AnimatedFloat(
-                Runnable {
-                    val scale: Float = barScale.value
-                    bubbleBarView.scaleX = scale
-                    bubbleBarView.scaleY = scale
-                }
-            )
+        barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value }
+        barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value }
         barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
 
         whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
         whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
-        whenever(bubbleBarViewController.bubbleBarScale).thenReturn(barScale)
+        whenever(bubbleBarViewController.bubbleBarScaleX).thenReturn(barScaleX)
+        whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(barScaleY)
         whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
+        whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
         whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
     }
 
@@ -317,7 +315,7 @@
         stashedHandleScale =
             AnimatedFloat(
                 Runnable {
-                    val scale: Float = barScale.value
+                    val scale: Float = barScaleX.value
                     bubbleBarView.scaleX = scale
                     bubbleBarView.scaleY = scale
                 }
@@ -327,6 +325,7 @@
         whenever(bubbleStashedHandleViewController.stashedHandleAlpha)
             .thenReturn(stashedHandleAlpha)
         whenever(bubbleStashedHandleViewController.physicsAnimator).thenReturn(stashPhysicsAnimator)
+        whenever(bubbleStashedHandleViewController.stashedWidth).thenReturn(HANDLE_VIEW_WIDTH)
         whenever(bubbleStashedHandleViewController.stashedHeight).thenReturn(HANDLE_VIEW_HEIGHT)
         whenever(bubbleStashedHandleViewController.setTranslationYForSwipe(any())).thenAnswer {
             invocation ->
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
new file mode 100644
index 0000000..2a0aa4c
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2024 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;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherRootView;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.util.SystemUiController;
+import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.system.InputConsumerController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Collections;
+import java.util.HashMap;
+
+public abstract class AbsSwipeUpHandlerTestCase<
+        RECENTS_CONTAINER extends Context & RecentsViewContainer,
+        STATE extends BaseState<STATE>,
+        RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+        ACTIVITY_TYPE extends  StatefulActivity<STATE> & RecentsViewContainer,
+        ACTIVITY_INTERFACE extends BaseActivityInterface<STATE, ACTIVITY_TYPE>,
+        SWIPE_HANDLER extends AbsSwipeUpHandler<RECENTS_CONTAINER, RECENTS_VIEW, STATE>> {
+
+    protected final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    protected final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(mContext);
+    protected final RecentsAnimationDeviceState mRecentsAnimationDeviceState =
+            new RecentsAnimationDeviceState(mContext, true);
+    protected final InputConsumerController mInputConsumerController =
+            InputConsumerController.getRecentsAnimationInputConsumer();
+    protected final ActivityManager.RunningTaskInfo mRunningTaskInfo =
+            new ActivityManager.RunningTaskInfo();
+    protected final TopTaskTracker.CachedTaskInfo mCachedTaskInfo =
+            new TopTaskTracker.CachedTaskInfo(Collections.singletonList(mRunningTaskInfo));
+    protected final RemoteAnimationTarget mRemoteAnimationTarget = new RemoteAnimationTarget(
+            /* taskId= */ 0,
+            /* mode= */ RemoteAnimationTarget.MODE_CLOSING,
+            /* leash= */ new SurfaceControl(),
+            /* isTranslucent= */ false,
+            /* clipRect= */ null,
+            /* contentInsets= */ null,
+            /* prefixOrderIndex= */ 0,
+            /* position= */ null,
+            /* localBounds= */ null,
+            /* screenSpaceBounds= */ null,
+            new Configuration().windowConfiguration,
+            /* isNotInRecents= */ false,
+            /* startLeash= */ null,
+            /* startBounds= */ null,
+            /* taskInfo= */ mRunningTaskInfo,
+            /* allowEnterPip= */ false);
+    protected final RecentsAnimationTargets mRecentsAnimationTargets = new RecentsAnimationTargets(
+            new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+            new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+            new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+            /* homeContentInsets= */ new Rect(),
+            /* minimizedHomeBounds= */ null,
+            new Bundle());
+
+    @Mock protected ACTIVITY_INTERFACE mActivityInterface;
+    @Mock protected ActivityInitListener<?> mActivityInitListener;
+    @Mock protected RecentsAnimationController mRecentsAnimationController;
+    @Mock protected STATE mState;
+    @Mock protected ViewTreeObserver mViewTreeObserver;
+    @Mock protected DragLayer mDragLayer;
+    @Mock protected LauncherRootView mRootView;
+    @Mock protected SystemUiController mSystemUiController;
+    @Mock protected GestureState mGestureState;
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Before
+    public void setUpRunningTaskInfo() {
+        mRunningTaskInfo.baseIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    @Before
+    public void setUpGestureState() {
+        when(mGestureState.getRunningTask()).thenReturn(mCachedTaskInfo);
+        when(mGestureState.getLastAppearedTaskIds()).thenReturn(new int[0]);
+        when(mGestureState.getLastStartedTaskIds()).thenReturn(new int[1]);
+        when(mGestureState.getHomeIntent()).thenReturn(new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        doReturn(mActivityInterface).when(mGestureState).getContainerInterface();
+    }
+
+    @Before
+    public void setUpRecentsView() {
+        RECENTS_VIEW recentsView = getRecentsView();
+        when(recentsView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+        doAnswer(answer -> {
+            runOnMainSync(() -> answer.<Runnable>getArgument(0).run());
+            return this;
+        }).when(recentsView).runOnPageScrollsInitialized(any());
+    }
+
+    @Before
+    public void setUpRecentsContainer() {
+        RecentsViewContainer recentsContainer = getRecentsContainer();
+        RECENTS_VIEW recentsView = getRecentsView();
+
+        when(recentsContainer.getDeviceProfile()).thenReturn(new DeviceProfile());
+        when(recentsContainer.getOverviewPanel()).thenReturn(recentsView);
+        when(recentsContainer.getDragLayer()).thenReturn(mDragLayer);
+        when(recentsContainer.getRootView()).thenReturn(mRootView);
+        when(recentsContainer.getSystemUiController()).thenReturn(mSystemUiController);
+        when(mActivityInterface.createActivityInitListener(any()))
+                .thenReturn(mActivityInitListener);
+        doReturn(recentsContainer).when(mActivityInterface).getCreatedContainer();
+        doAnswer(answer -> {
+            answer.<Runnable>getArgument(0).run();
+            return this;
+        }).when(recentsContainer).runOnBindToTouchInteractionService(any());
+    }
+
+    @Test
+    public void testInitWhenReady_registersActivityInitListener() {
+        String reasonString = "because i said so";
+
+        createSwipeHandler().initWhenReady(reasonString);
+        verify(mActivityInitListener).register(eq(reasonString));
+    }
+
+    @Test
+    public void testOnRecentsAnimationCanceled_unregistersActivityInitListener() {
+        createSwipeHandler()
+                .onRecentsAnimationCanceled(new HashMap<>());
+
+        runOnMainSync(() -> verify(mActivityInitListener)
+                .unregister(eq("AbsSwipeUpHandler.onRecentsAnimationCanceled")));
+    }
+
+    @Test
+    public void testOnConsumerAboutToBeSwitched_unregistersActivityInitListener() {
+        createSwipeHandler().onConsumerAboutToBeSwitched();
+
+        runOnMainSync(() -> verify(mActivityInitListener)
+                .unregister("AbsSwipeUpHandler.invalidateHandler"));
+    }
+
+    @Test
+    public void testOnConsumerAboutToBeSwitched_midQuickSwitch_unregistersActivityInitListener() {
+        createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.NEW_TASK)
+                .onConsumerAboutToBeSwitched();
+
+        runOnMainSync(() -> verify(mActivityInitListener)
+                .unregister(eq("AbsSwipeUpHandler.cancelCurrentAnimation")));
+    }
+
+    @Test
+    public void testStartNewTask_finishesRecentsAnimationController() {
+        SWIPE_HANDLER absSwipeUpHandler = createSwipeHandler();
+
+        onRecentsAnimationStart(absSwipeUpHandler);
+
+        runOnMainSync(() -> {
+            absSwipeUpHandler.startNewTask(unused -> {});
+            verify(mRecentsAnimationController).finish(anyBoolean(), any());
+        });
+    }
+
+    @Test
+    public void testHomeGesture_finishesRecentsAnimationController() {
+        createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME);
+
+        runOnMainSync(() -> {
+            verify(mRecentsAnimationController).detachNavigationBarFromApp(true);
+            verify(mRecentsAnimationController).finish(anyBoolean(), any(), anyBoolean());
+        });
+    }
+
+    private SWIPE_HANDLER createSwipeUpHandlerForGesture(GestureState.GestureEndTarget endTarget) {
+        boolean isQuickSwitch = endTarget == GestureState.GestureEndTarget.NEW_TASK;
+
+        doReturn(mState).when(mActivityInterface).stateFromGestureEndTarget(any());
+
+        SWIPE_HANDLER swipeHandler = createSwipeHandler(SystemClock.uptimeMillis(), isQuickSwitch);
+
+        swipeHandler.onActivityInit(/* alreadyOnHome= */ false);
+        swipeHandler.onGestureStarted(isQuickSwitch);
+        onRecentsAnimationStart(swipeHandler);
+
+        when(mGestureState.getRunningTaskIds(anyBoolean())).thenReturn(new int[0]);
+        runOnMainSync(swipeHandler::switchToScreenshot);
+
+        when(mGestureState.getEndTarget()).thenReturn(endTarget);
+        when(mGestureState.isRecentsAnimationRunning()).thenReturn(isQuickSwitch);
+        float xVelocityPxPerMs = isQuickSwitch ? 100 : 0;
+        float yVelocityPxPerMs = isQuickSwitch ? 0 : -100;
+        swipeHandler.onGestureEnded(
+                yVelocityPxPerMs, new PointF(xVelocityPxPerMs, yVelocityPxPerMs));
+        swipeHandler.onCalculateEndTarget();
+        runOnMainSync(swipeHandler::onSettledOnEndTarget);
+
+        return swipeHandler;
+    }
+
+    private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
+        when(mActivityInterface.getOverviewWindowBounds(any(), any())).thenReturn(new Rect());
+        doNothing().when(mActivityInterface).setOnDeferredActivityLaunchCallback(any());
+
+        runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
+                mRecentsAnimationController, mRecentsAnimationTargets));
+    }
+
+    private static void runOnMainSync(Runnable runnable) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+    }
+
+    @NonNull
+    private SWIPE_HANDLER createSwipeHandler() {
+        return createSwipeHandler(SystemClock.uptimeMillis(), false);
+    }
+
+    @NonNull
+    protected abstract SWIPE_HANDLER createSwipeHandler(
+            long touchTimeMs, boolean continuingLastGesture);
+
+    @NonNull
+    protected abstract RecentsViewContainer getRecentsContainer();
+
+    @NonNull
+    protected abstract RECENTS_VIEW getRecentsView();
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
new file mode 100644
index 0000000..dd0b4b3
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 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;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsState;
+
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class FallbackSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase<
+        RecentsActivity,
+        RecentsState,
+        FallbackRecentsView,
+        RecentsActivity,
+        FallbackActivityInterface,
+        FallbackSwipeHandler> {
+
+    @Mock private RecentsActivity mRecentsActivity;
+    @Mock private FallbackRecentsView mRecentsView;
+
+
+    @Override
+    protected FallbackSwipeHandler createSwipeHandler(
+            long touchTimeMs, boolean continuingLastGesture) {
+        return new FallbackSwipeHandler(
+                mContext,
+                mRecentsAnimationDeviceState,
+                mTaskAnimationManager,
+                mGestureState,
+                touchTimeMs,
+                continuingLastGesture,
+                mInputConsumerController);
+    }
+
+    @Override
+    protected RecentsActivity getRecentsContainer() {
+        return mRecentsActivity;
+    }
+
+    @Override
+    protected FallbackRecentsView getRecentsView() {
+        return mRecentsView;
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
new file mode 100644
index 0000000..653dc01
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 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;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.WorkspaceStateTransitionAnimation;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.views.RecentsView;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase<
+        QuickstepLauncher,
+        LauncherState,
+        RecentsView<QuickstepLauncher, LauncherState>,
+        QuickstepLauncher,
+        LauncherActivityInterface,
+        LauncherSwipeHandlerV2> {
+
+    @Mock private QuickstepLauncher mQuickstepLauncher;
+    @Mock private RecentsView<QuickstepLauncher, LauncherState> mRecentsView;
+    @Mock private Workspace<?> mWorkspace;
+    @Mock private Hotseat mHotseat;
+    @Mock private WorkspaceStateTransitionAnimation mTransitionAnimation;
+
+    @Before
+    public void setUpQuickStepLauncher() {
+        when(mQuickstepLauncher.createAtomicAnimationFactory())
+                .thenReturn(new AtomicAnimationFactory<>(0));
+        when(mQuickstepLauncher.getHotseat()).thenReturn(mHotseat);
+        doReturn(mWorkspace).when(mQuickstepLauncher).getWorkspace();
+        doReturn(new StateManager(mQuickstepLauncher, LauncherState.NORMAL))
+                .when(mQuickstepLauncher).getStateManager();
+
+    }
+
+    @Before
+    public void setUpWorkspace() {
+        when(mWorkspace.getStateTransitionAnimation()).thenReturn(mTransitionAnimation);
+    }
+
+    @Override
+    protected LauncherSwipeHandlerV2 createSwipeHandler(
+            long touchTimeMs, boolean continuingLastGesture) {
+        return new LauncherSwipeHandlerV2(
+                mContext,
+                mRecentsAnimationDeviceState,
+                mTaskAnimationManager,
+                mGestureState,
+                touchTimeMs,
+                continuingLastGesture,
+                mInputConsumerController);
+    }
+
+    @Override
+    protected QuickstepLauncher getRecentsContainer() {
+        return mQuickstepLauncher;
+    }
+
+    @Override
+    protected RecentsView<QuickstepLauncher, LauncherState> getRecentsView() {
+        return mRecentsView;
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
new file mode 100644
index 0000000..0ae710f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2024 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
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.TestDispatcherProvider
+import com.android.launcher3.util.rule.setFlags
+import com.android.quickstep.OverviewCommandHelper.CommandInfo
+import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus
+import com.android.quickstep.OverviewCommandHelper.CommandType
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class OverviewCommandHelperTest {
+    @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
+    private lateinit var sut: OverviewCommandHelper
+    private val dispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(dispatcher)
+
+    private var pendingCallbacksWithDelays = mutableListOf<Long>()
+
+    @Suppress("UNCHECKED_CAST")
+    @Before
+    fun setup() {
+        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_OVERVIEW_COMMAND_HELPER_TIMEOUT)
+
+        sut =
+            spy(
+                OverviewCommandHelper(
+                    touchInteractionService = mock(),
+                    overviewComponentObserver = mock(),
+                    taskAnimationManager = mock(),
+                    dispatcherProvider = TestDispatcherProvider(dispatcher)
+                )
+            )
+
+        doAnswer { invocation ->
+                val pendingCallback = invocation.arguments[1] as () -> Unit
+
+                val delayInMillis = pendingCallbacksWithDelays.removeFirstOrNull()
+                if (delayInMillis != null) {
+                    runBlocking {
+                        testScope.backgroundScope.launch {
+                            delay(delayInMillis)
+                            pendingCallback.invoke()
+                        }
+                    }
+                }
+                delayInMillis == null // if no callback to execute, returns success
+            }
+            .`when`(sut)
+            .executeCommand(any<CommandInfo>(), any())
+    }
+
+    private fun addCallbackDelay(delayInMillis: Long = 0) {
+        pendingCallbacksWithDelays.add(delayInMillis)
+    }
+
+    @Test
+    fun whenFirstCommandIsAdded_executeCommandImmediately() =
+        testScope.runTest {
+            // Add command to queue
+            val commandInfo: CommandInfo = sut.addCommand(CommandType.HOME)!!
+            assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
+            runCurrent()
+            assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED)
+        }
+
+    @Test
+    fun whenFirstCommandIsAdded_executeCommandImmediately_WithCallbackDelay() =
+        testScope.runTest {
+            addCallbackDelay(100)
+
+            // Add command to queue
+            val commandType = CommandType.HOME
+            val commandInfo: CommandInfo = sut.addCommand(commandType)!!
+            assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
+
+            runCurrent()
+            assertThat(commandInfo.status).isEqualTo(CommandStatus.PROCESSING)
+
+            advanceTimeBy(200L)
+            assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED)
+        }
+
+    @Test
+    fun whenFirstCommandIsPendingCallback_NextCommandWillWait() =
+        testScope.runTest {
+            // Add command to queue
+            addCallbackDelay(100)
+            val commandType1 = CommandType.HOME
+            val commandInfo1: CommandInfo = sut.addCommand(commandType1)!!
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE)
+
+            addCallbackDelay(100)
+            val commandType2 = CommandType.SHOW
+            val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+            runCurrent()
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+            advanceTimeBy(101L)
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.COMPLETED)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
+
+            advanceTimeBy(101L)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED)
+        }
+
+    @Test
+    fun whenCommandTakesTooLong_TriggerTimeout_AndExecuteNextCommand() =
+        testScope.runTest {
+            // Add command to queue
+            addCallbackDelay(QUEUE_TIMEOUT)
+            val commandType1 = CommandType.HOME
+            val commandInfo1: CommandInfo = sut.addCommand(commandType1)!!
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE)
+
+            addCallbackDelay(100)
+            val commandType2 = CommandType.SHOW
+            val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+            runCurrent()
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+            advanceTimeBy(QUEUE_TIMEOUT)
+            assertThat(commandInfo1.status).isEqualTo(CommandStatus.CANCELED)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
+
+            advanceTimeBy(101)
+            assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED)
+        }
+
+    private companion object {
+        const val QUEUE_TIMEOUT = 5001L
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
index 80b9489..c18f604 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
@@ -25,6 +25,7 @@
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.quickstep.DeviceConfigWrapper.DEFAULT_LPNH_TIMEOUT_MS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -39,7 +40,6 @@
 
 import android.os.SystemClock;
 import android.view.MotionEvent;
-import android.view.ViewConfiguration;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -142,7 +142,7 @@
     @Test
     public void testLongPressTriggered() {
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -156,7 +156,7 @@
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
         mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
                 -(TOUCH_SLOP - 1)));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -170,7 +170,7 @@
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
         mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
                 mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -189,7 +189,7 @@
             mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
                     mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
             // We have entered the second stage, so the normal timeout shouldn't trigger.
-            SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+            SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
             assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -200,7 +200,7 @@
             // After an extended time, the long press should trigger.
             float extendedDurationMultiplier =
                     (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
-            SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+            SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
                     * (extendedDurationMultiplier - 1)));  // -1 because we already waited 1x
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
@@ -221,7 +221,7 @@
 
             mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
             // We have not entered the second stage, so the normal timeout should trigger.
-            SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+            SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
             assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -236,7 +236,7 @@
     @Test
     public void testLongPressAbortedByTouchUp() {
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -256,7 +256,7 @@
     @Test
     public void testLongPressAbortedByTouchCancel() {
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -276,7 +276,7 @@
     @Test
     public void testLongPressAbortedByTouchSlopPassedVertically() {
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -297,7 +297,7 @@
     @Test
     public void testLongPressAbortedByTouchSlopPassedHorizontally() {
         mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -326,7 +326,7 @@
             mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
                     -(TOUCH_SLOP - 1)));
             // Normal duration shouldn't trigger.
-            SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+            SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
             assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -338,7 +338,7 @@
             // Wait past the extended long press timeout, to be sure it wouldn't have triggered.
             float extendedDurationMultiplier =
                     (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
-            SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+            SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
                     * (extendedDurationMultiplier - 1)));  // -1 because we already waited 1x
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
@@ -363,7 +363,7 @@
             mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
                     mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
             // Normal duration shouldn't trigger.
-            SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+            SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
             assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -375,7 +375,7 @@
             // Wait past the extended long press timeout, to be sure it wouldn't have triggered.
             float extendedDurationMultiplier =
                     (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
-            SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+            SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
                     * (extendedDurationMultiplier - 1)));  // -1 because we already waited 1x
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
@@ -393,7 +393,7 @@
     public void testTouchOutsideNavHandleIgnored() {
         // Touch the far left side of the screen. (y=0 is top of navbar region, picked arbitrarily)
         mUnderTest.onMotionEvent(generateMotionEvent(ACTION_DOWN, 0, 0));
-        SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+        SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         // Should be ignored because the x position was not centered in the navbar region.
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index d2479bc..7c48ea4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -34,9 +34,6 @@
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
 import com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY
-import com.google.android.apps.nexuslauncher.PrefKey.KEY_ENABLE_MINUS_ONE
-import com.google.android.apps.nexuslauncher.PrefKey.OVERVIEW_SUGGESTED_ACTIONS
-import com.google.android.apps.nexuslauncher.PrefKey.SMARTSPACE_ON_HOME_SCREEN
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
@@ -141,7 +138,14 @@
             .isTrue()
         assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED.id })
             .isTrue()
-        // LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED
-        assertThat(capturedEvents.any { it.id == 617 }).isTrue()
+        assertThat(capturedEvents.any { it.id == LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED }).isTrue()
+    }
+
+    companion object {
+        private const val KEY_ENABLE_MINUS_ONE = "pref_enable_minus_one"
+        private const val OVERVIEW_SUGGESTED_ACTIONS = "pref_overview_action_suggestions"
+        private const val SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen"
+
+        private const val LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED = 617
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..7d09efd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+class FakeHighResLoadingStateNotifier : HighResLoadingStateNotifier {
+    val listeners = mutableListOf<HighResLoadingStateChangedCallback>()
+
+    override fun addCallback(callback: HighResLoadingStateChangedCallback) {
+        listeners.add(callback)
+    }
+
+    override fun removeCallback(callback: HighResLoadingStateChangedCallback) {
+        listeners.remove(callback)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
index cdfbd16..fc2f029 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
@@ -20,8 +20,6 @@
     private var recentsDeviceProfile =
         RecentsDeviceProfile(
             isLargeScreen = false,
-            widthPx = 1080,
-            heightPx = 1920,
         )
 
     override fun getRecentsDeviceProfile() = recentsDeviceProfile
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
index fee4979..5de876a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
@@ -27,7 +27,8 @@
 
 class FakeTaskIconDataSource : TaskIconDataSource {
 
-    val taskIdToDrawable: Map<Int, Drawable> = (0..10).associateWith { mockCopyableDrawable() }
+    val taskIdToDrawable: MutableMap<Int, Drawable> =
+        (0..10).associateWith { mockCopyableDrawable() }.toMutableMap()
 
     val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
     var shouldLoadSynchronously: Boolean = true
@@ -52,15 +53,17 @@
         return null
     }
 
-    private fun mockCopyableDrawable(): Drawable {
-        val mutableDrawable = mock<Drawable>()
-        val immutableDrawable =
-            mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
-        val constantState =
-            mock<Drawable.ConstantState>().apply {
-                whenever(newDrawable()).thenReturn(immutableDrawable)
-            }
-        return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+    companion object {
+        fun mockCopyableDrawable(): Drawable {
+            val mutableDrawable = mock<Drawable>()
+            val immutableDrawable =
+                mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
+            val constantState =
+                mock<Drawable.ConstantState>().apply {
+                    whenever(newDrawable()).thenReturn(immutableDrawable)
+                }
+            return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+        }
     }
 }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
index 30fc491..d12c0b0 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -27,7 +27,8 @@
 
 class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
 
-    val taskIdToBitmap: Map<Int, Bitmap> = (0..10).associateWith { mock() }
+    val taskIdToBitmap: MutableMap<Int, Bitmap> =
+        (0..10).associateWith { mock<Bitmap>() }.toMutableMap()
     val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
     var shouldLoadSynchronously: Boolean = true
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..765f0d1
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+class FakeTaskVisualsChangeNotifier : TaskVisualsChangeNotifier {
+    val listeners = mutableListOf<TaskVisualsChangeListener>()
+
+    override fun addThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+        listeners.add(listener)
+    }
+
+    override fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+        listeners.remove(listener)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
index d94a351..7a17872 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -28,7 +28,6 @@
     private var taskIconDataMap: Map<Int, TaskIconQueryResponse> = emptyMap()
     private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
     private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
-    private var thumbnailOverrideMap: Map<Int, ThumbnailData> = emptyMap()
 
     override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
 
@@ -39,7 +38,7 @@
             .map { taskList ->
                 val task = taskList.firstOrNull { it.key.id == taskId } ?: return@map null
                 Task(task).apply {
-                    thumbnail = thumbnailOverrideMap[taskId] ?: task.thumbnail
+                    thumbnail = task.thumbnail
                     icon = task.icon
                     titleDescription = task.titleDescription
                     title = task.title
@@ -62,16 +61,6 @@
                     }
                 }
             }
-        setThumbnailOverrideInternal(thumbnailOverrideMap)
-    }
-
-    override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
-        setThumbnailOverrideInternal(thumbnailOverride)
-    }
-
-    private fun setThumbnailOverrideInternal(thumbnailOverride: Map<Int, ThumbnailData>) {
-        thumbnailOverrideMap =
-            thumbnailOverride.filterKeys(this.visibleTasks.value::contains).toMap()
     }
 
     fun seedTasks(tasks: List<Task>) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
index e74fe4b..abe4142 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
@@ -39,6 +39,6 @@
         whenever(recentsViewContainer.deviceProfile).thenReturn(tabletDeviceProfile)
 
         assertThat(systemUnderTest.getRecentsDeviceProfile())
-            .isEqualTo(RecentsDeviceProfile(isLargeScreen = true, widthPx = 1600, heightPx = 2560))
+            .isEqualTo(RecentsDeviceProfile(isLargeScreen = true))
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
new file mode 100644
index 0000000..41f6bfd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2024 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.recents.data
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.UserHandle
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+class TaskVisualsChangedDelegateTest {
+    private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+    private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+
+    val systemUnderTest =
+        TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
+
+    @Test
+    fun addingFirstListener_addsListenerToNotifiers() {
+        systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+
+        assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+        assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+    }
+
+    @Test
+    fun addingAndRemovingListener_removesListenerFromNotifiers() {
+        systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+        systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+        assertThat(taskVisualsChangeNotifier.listeners).isEmpty()
+        assertThat(highResLoadingStateNotifier.listeners).isEmpty()
+    }
+
+    @Test
+    fun addingTwoAndRemovingOneListener_doesNotRemoveListenerFromNotifiers() {
+        systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+        systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 2), mock())
+        systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+        assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+        assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+    }
+
+    @Test
+    fun onTaskIconChangedWithTaskId_notifiesCorrectListenerOnly() {
+        val expectedListener = mock<TaskIconChangedCallback>()
+        val additionalListener = mock<TaskIconChangedCallback>()
+        systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 1), expectedListener)
+        systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 2), additionalListener)
+
+        systemUnderTest.onTaskIconChanged(1)
+
+        verify(expectedListener).onTaskIconChanged()
+        verifyNoMoreInteractions(additionalListener)
+    }
+
+    @Test
+    fun onTaskIconChangedWithoutTaskId_notifiesCorrectListenerOnly() {
+        val expectedListener = mock<TaskIconChangedCallback>()
+        val listener = mock<TaskIconChangedCallback>()
+        // Correct match
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+            expectedListener
+        )
+        // 1 out of 2 match
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 2, pkg = PACKAGE_NAME, userId = 1),
+            listener
+        )
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 3, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 2),
+            listener
+        )
+        // 0 out of 2 match
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 4, pkg = PACKAGE_NAME, userId = 2),
+            listener
+        )
+
+        systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+        verify(expectedListener).onTaskIconChanged()
+        verifyNoMoreInteractions(listener)
+    }
+
+    @Test
+    fun replacedTaskIconChangedCallbacks_notCalled() {
+        val replacedListener = mock<TaskIconChangedCallback>()
+        val newListener = mock<TaskIconChangedCallback>()
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+            replacedListener
+        )
+        systemUnderTest.registerTaskIconChangedCallback(
+            createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+            newListener
+        )
+
+        systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+        verifyNoMoreInteractions(replacedListener)
+        verify(newListener).onTaskIconChanged()
+    }
+
+    @Test
+    fun onTaskThumbnailChanged_notifiesCorrectListenerOnly() {
+        val expectedListener = mock<TaskThumbnailChangedCallback>()
+        val additionalListener = mock<TaskThumbnailChangedCallback>()
+        val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+        systemUnderTest.registerTaskThumbnailChangedCallback(
+            createTaskKey(id = 1),
+            expectedListener
+        )
+        systemUnderTest.registerTaskThumbnailChangedCallback(
+            createTaskKey(id = 2),
+            additionalListener
+        )
+
+        systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+        verify(expectedListener).onTaskThumbnailChanged(expectedThumbnailData)
+        verifyNoMoreInteractions(additionalListener)
+    }
+
+    @Test
+    fun onHighResLoadingStateChanged_notifiesAllListeners() {
+        val expectedListener = mock<TaskThumbnailChangedCallback>()
+        val additionalListener = mock<TaskThumbnailChangedCallback>()
+        systemUnderTest.registerTaskThumbnailChangedCallback(
+            createTaskKey(id = 1),
+            expectedListener
+        )
+        systemUnderTest.registerTaskThumbnailChangedCallback(
+            createTaskKey(id = 2),
+            additionalListener
+        )
+
+        systemUnderTest.onHighResLoadingStateChanged(true)
+
+        verify(expectedListener).onHighResLoadingStateChanged()
+        verify(additionalListener).onHighResLoadingStateChanged()
+    }
+
+    @Test
+    fun replacedTaskThumbnailChangedCallbacks_notCalled() {
+        val replacedListener1 = mock<TaskThumbnailChangedCallback>()
+        val newListener1 = mock<TaskThumbnailChangedCallback>()
+        val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+        systemUnderTest.registerTaskThumbnailChangedCallback(
+            createTaskKey(id = 1),
+            replacedListener1
+        )
+        systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), newListener1)
+
+        systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+        verifyNoMoreInteractions(replacedListener1)
+        verify(newListener1).onTaskThumbnailChanged(expectedThumbnailData)
+    }
+
+    private fun createTaskKey(id: Int = 1, pkg: String = PACKAGE_NAME, userId: Int = 1) =
+        TaskKey(id, 0, Intent().setPackage(pkg), ComponentName("", ""), userId, 0)
+
+    private companion object {
+        const val PACKAGE_NAME = "com.test.test"
+        const val ALTERNATIVE_PACKAGE_NAME = "com.test.test2"
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index e6534eb..f31467f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -19,7 +19,7 @@
 import android.content.ComponentName
 import android.content.Intent
 import android.graphics.Bitmap
-import android.view.Surface
+import android.graphics.drawable.Drawable
 import com.android.launcher3.util.TestDispatcherProvider
 import com.android.quickstep.task.thumbnail.TaskThumbnailViewModelTest
 import com.android.quickstep.util.DesktopTask
@@ -29,6 +29,9 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
@@ -48,6 +51,10 @@
     private val recentsModel = FakeRecentTasksDataSource()
     private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
     private val taskIconDataSource = FakeTaskIconDataSource()
+    private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+    private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+    private val taskVisualsChangedDelegate =
+        TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
 
     private val dispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(dispatcher)
@@ -56,6 +63,7 @@
             recentsModel,
             taskThumbnailDataSource,
             taskIconDataSource,
+            taskVisualsChangedDelegate,
             testScope.backgroundScope,
             TestDispatcherProvider(dispatcher)
         )
@@ -203,87 +211,81 @@
         }
 
     @Test
-    fun addThumbnailOverrideOverrideThumbnails() =
+    fun onTaskThumbnailChanged_setsNewThumbnailDataOnTask() =
         testScope.runTest {
             recentsModel.seedTasks(defaultTaskList)
-            val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-            val thumbnailOverride2 = createThumbnailData()
-            systemUnderTest.getAllTaskData(forceRefresh = true)
-
-            systemUnderTest.setVisibleTasks(listOf(1, 2))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
-
-            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
-            assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
-                .isEqualTo(thumbnailOverride2.thumbnail)
-        }
-
-    @Test
-    fun addThumbnailOverrideMultipleOverrides() =
-        testScope.runTest {
-            recentsModel.seedTasks(defaultTaskList)
-            val thumbnailOverride1 = createThumbnailData()
-            val thumbnailOverride2 = createThumbnailData()
-            val thumbnailOverride3 = createThumbnailData()
-            systemUnderTest.getAllTaskData(forceRefresh = true)
-
-            systemUnderTest.setVisibleTasks(listOf(1, 2))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride3))
-
-            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
-                .isEqualTo(thumbnailOverride1.thumbnail)
-            assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
-                .isEqualTo(thumbnailOverride3.thumbnail)
-        }
-
-    @Test
-    fun addThumbnailOverrideClearedWhenTaskBecomeInvisible() =
-        testScope.runTest {
-            recentsModel.seedTasks(defaultTaskList)
-            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-            val thumbnailOverride1 = createThumbnailData()
-            val thumbnailOverride2 = createThumbnailData()
-            systemUnderTest.getAllTaskData(forceRefresh = true)
-
-            systemUnderTest.setVisibleTasks(listOf(1, 2))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
-            // Making task 2 invisible and visible again should clear the override
-            systemUnderTest.setVisibleTasks(listOf(1))
-            systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
-                .isEqualTo(thumbnailOverride1.thumbnail)
-            assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
-        }
-
-    @Test
-    fun addThumbnailOverrideDoesNotOverrideInvisibleTasks() =
-        testScope.runTest {
-            recentsModel.seedTasks(defaultTaskList)
-            val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-            val thumbnailOverride = createThumbnailData()
             systemUnderTest.getAllTaskData(forceRefresh = true)
 
             systemUnderTest.setVisibleTasks(listOf(1))
-            systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride))
-            systemUnderTest.setVisibleTasks(listOf(1, 2))
 
-            assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
-            assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
+            val expectedThumbnailData = createThumbnailData()
+            val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+            val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+            val task1ThumbnailValues = mutableListOf<ThumbnailData?>()
+            testScope.backgroundScope.launch {
+                taskDataFlow.map { it?.thumbnail }.toList(task1ThumbnailValues)
+            }
+            taskVisualsChangedDelegate.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+            assertThat(task1ThumbnailValues[1]!!.thumbnail).isEqualTo(expectedPreviousBitmap)
+            assertThat(task1ThumbnailValues.last()).isEqualTo(expectedThumbnailData)
+        }
+
+    @Test
+    fun onHighResLoadingStateChanged_setsNewThumbnailDataOnTask() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+
+            systemUnderTest.setVisibleTasks(listOf(1))
+
+            val expectedBitmap = mock<Bitmap>()
+            val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+            val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+            val task1ThumbnailValues = mutableListOf<Bitmap?>()
+            testScope.backgroundScope.launch {
+                taskDataFlow.map { it?.thumbnail?.thumbnail }.toList(task1ThumbnailValues)
+            }
+            taskThumbnailDataSource.taskIdToBitmap[1] = expectedBitmap
+            taskVisualsChangedDelegate.onHighResLoadingStateChanged(true)
+
+            assertThat(task1ThumbnailValues[1]).isEqualTo(expectedPreviousBitmap)
+            assertThat(task1ThumbnailValues.last()).isEqualTo(expectedBitmap)
+        }
+
+    @Test
+    fun onTaskIconChanged_setsNewIconOnTask() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+
+            systemUnderTest.setVisibleTasks(listOf(1))
+
+            val expectedIcon = FakeTaskIconDataSource.mockCopyableDrawable()
+            val expectedPreviousIcon = taskIconDataSource.taskIdToDrawable[1]
+            val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+            val task1IconValues = mutableListOf<Drawable?>()
+            testScope.backgroundScope.launch {
+                taskDataFlow.map { it?.icon }.toList(task1IconValues)
+            }
+            taskIconDataSource.taskIdToDrawable[1] = expectedIcon
+            taskVisualsChangedDelegate.onTaskIconChanged(1)
+
+            assertThat(task1IconValues[1]).isEqualTo(expectedPreviousIcon)
+            assertThat(task1IconValues.last()).isEqualTo(expectedIcon)
         }
 
     private fun createTaskWithId(taskId: Int) =
         Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
 
-    private fun createThumbnailData(rotation: Int = Surface.ROTATION_0): ThumbnailData {
+    private fun createThumbnailData(): ThumbnailData {
         val bitmap = mock<Bitmap>()
         whenever(bitmap.width).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_WIDTH)
         whenever(bitmap.height).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_HEIGHT)
 
-        return ThumbnailData(thumbnail = bitmap, rotation = rotation)
+        return ThumbnailData(thumbnail = bitmap)
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
index dc16475..fe67313 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
@@ -70,44 +70,6 @@
         assertThat(thumbnailDataFlow2.first()).isNull()
     }
 
-    @Test
-    fun thumbnailOverrideWaitAndReset() = runTest {
-        val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
-        val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
-        tasksRepository.seedTasks(tasks)
-        tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
-
-        val thumbnailDataFlow1 = tasksRepository.getThumbnailById(1)
-        val thumbnailDataFlow2 = tasksRepository.getThumbnailById(2)
-
-        systemUnderTest.refreshAllTaskData()
-        systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
-        assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
-        assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
-
-        systemUnderTest.setRunningTaskShowScreenshot(true)
-        val thumbnailOverride = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
-        systemUnderTest.addOrUpdateThumbnailOverride(thumbnailOverride)
-
-        systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
-        val expectedUpdate = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
-        systemUnderTest.waitForThumbnailsToUpdate(expectedUpdate)
-
-        assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
-        assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
-
-        systemUnderTest.onReset()
-
-        assertThat(thumbnailDataFlow1.first()).isNull()
-        assertThat(thumbnailDataFlow2.first()).isNull()
-
-        systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
-        assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
-        assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
-    }
-
     private fun createTaskWithId(taskId: Int) =
         Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
             colorBackground = Color.argb(taskId, taskId, taskId, taskId)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt
deleted file mode 100644
index 13e8b09..0000000
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2024 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.task.thumbnail
-
-import android.graphics.Point
-import android.graphics.drawable.Drawable
-import com.android.quickstep.recents.data.FakeRecentsDeviceProfileRepository
-import com.android.quickstep.task.viewmodel.TaskViewData
-import com.android.quickstep.views.TaskViewType
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
-
-class GetSplashSizeUseCaseTest {
-    private val taskThumbnailViewData = TaskThumbnailViewData()
-    private val taskViewData = TaskViewData(TaskViewType.SINGLE)
-    private val recentsDeviceProfileRepository = FakeRecentsDeviceProfileRepository()
-    private val systemUnderTest =
-        GetSplashSizeUseCase(taskThumbnailViewData, taskViewData, recentsDeviceProfileRepository)
-
-    @Test
-    fun execute_whenNoScaleRequired_returnsIntrinsicSize() {
-        taskThumbnailViewData.width.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx
-        taskThumbnailViewData.height.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx
-
-        assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(100, 100))
-    }
-
-    @Test
-    fun execute_whenThumbnailViewIsSmallerThanScreen_returnsScaledSize() {
-        taskThumbnailViewData.width.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
-        taskThumbnailViewData.height.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
-
-        assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(50, 50))
-    }
-
-    @Test
-    fun execute_whenThumbnailViewIsSmallerThanScreen_withNonGridScale_returnsScaledSize() {
-        taskThumbnailViewData.width.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
-        taskThumbnailViewData.height.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
-        taskViewData.nonGridScale.value = 2f
-
-        assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(25, 25))
-    }
-
-    @Test
-    fun execute_whenThumbnailViewIsSmallerThanScreen_withThumbnailViewScale_returnsScaledSize() {
-        taskThumbnailViewData.width.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
-        taskThumbnailViewData.height.value =
-            recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
-        taskThumbnailViewData.scaleX.value = 2f
-        taskThumbnailViewData.scaleY.value = 2f
-
-        assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(25, 25))
-    }
-
-    private fun createIcon(width: Int, height: Int): Drawable =
-        mock<Drawable>().apply {
-            whenever(intrinsicWidth).thenReturn(width)
-            whenever(intrinsicHeight).thenReturn(height)
-        }
-}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
index fe7d37a..fcf4e56 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -21,7 +21,6 @@
 import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.Matrix
-import android.graphics.Point
 import android.graphics.drawable.Drawable
 import android.view.Surface
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -35,7 +34,6 @@
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
-import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Splash
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.quickstep.task.viewmodel.TaskContainerData
 import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
@@ -46,10 +44,8 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 
@@ -63,7 +59,6 @@
     private val tasksRepository = FakeTasksRepository()
     private val mGetThumbnailPositionUseCase = mock<GetThumbnailPositionUseCase>()
     private val splashAlphaUseCase: SplashAlphaUseCase = mock()
-    private val getSplashSizeUseCase: GetSplashSizeUseCase = mock()
     private val systemUnderTest by lazy {
         TaskThumbnailViewModel(
             recentsViewData,
@@ -72,17 +67,11 @@
             tasksRepository,
             mGetThumbnailPositionUseCase,
             splashAlphaUseCase,
-            getSplashSizeUseCase,
         )
     }
 
     private val tasks = (0..5).map(::createTaskWithId)
 
-    @Before
-    fun setUp() {
-        whenever(getSplashSizeUseCase.execute(any())).thenReturn(Point())
-    }
-
     @Test
     fun initialStateIsUninitialized() = runTest {
         assertThat(systemUnderTest.uiState.first()).isEqualTo(Uninitialized)
@@ -120,7 +109,7 @@
                         bitmap = expectedThumbnailData.thumbnail!!,
                         thumbnailRotation = Surface.ROTATION_0,
                     ),
-                    Splash(expectedIconData.icon, Point())
+                    expectedIconData.icon
                 )
             )
     }
@@ -215,7 +204,7 @@
                         bitmap = expectedThumbnailData.thumbnail!!,
                         thumbnailRotation = Surface.ROTATION_270,
                     ),
-                    Splash(expectedIconData.icon, Point())
+                    expectedIconData.icon
                 )
             )
     }
@@ -241,29 +230,12 @@
                         bitmap = expectedThumbnailData.thumbnail!!,
                         thumbnailRotation = Surface.ROTATION_0,
                     ),
-                    Splash(expectedIconData.icon, Point())
+                    expectedIconData.icon
                 )
             )
     }
 
     @Test
-    fun bindStoppedTask_thenStateContainsSplashSizeFromUseCase() = runTest {
-        val taskId = 2
-        val expectedSplashSize = Point(100, 150)
-        whenever(getSplashSizeUseCase.execute(any())).thenReturn(expectedSplashSize)
-        val expectedThumbnailData = createThumbnailData(rotation = Surface.ROTATION_270)
-        tasksRepository.seedThumbnailData(mapOf(taskId to expectedThumbnailData))
-        val expectedIconData = createIconData("Task 2")
-        tasksRepository.seedIconData(mapOf(taskId to expectedIconData))
-        tasksRepository.seedTasks(tasks)
-        tasksRepository.setVisibleTasks(listOf(taskId))
-
-        systemUnderTest.bind(taskId)
-        val uiState = systemUnderTest.uiState.first() as SnapshotSplash
-        assertThat(uiState.splash.size).isEqualTo(expectedSplashSize)
-    }
-
-    @Test
     fun getSnapshotMatrix_MissingThumbnail() = runTest {
         val taskId = 2
         val isRtl = true
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 15b1e53..d064f4a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -57,6 +57,7 @@
     @Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
     @Mock lateinit var taskbarPinningController: TaskbarPinningController
     @Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers>
+    @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
 
     lateinit var taskbarControllers: TaskbarControllers
 
@@ -98,6 +99,7 @@
                 keyboardQuickSwitchController,
                 taskbarPinningController,
                 optionalBubbleControllers,
+                taskbarDesktopModeController
             )
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index d9d5585..885a7f6 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -39,8 +39,8 @@
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.Task.TaskKey
 import com.android.window.flags.Flags
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index cbc8441..244b897 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -39,7 +39,7 @@
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.TaskViewType;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 6e25b10..e981570 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -67,15 +67,15 @@
             mLauncher.goHome();
             final DigitalWellBeingToast toast = getToast();
 
-            waitForLauncherCondition("Toast is not visible", launcher -> toast.hasLimit());
-            assertEquals("Toast text: ", "5 minutes left today", toast.getText());
+            waitForLauncherCondition("Toast is not visible", launcher -> toast.getHasLimit());
+            assertEquals("Toast text: ", "5 minutes left today", toast.getBannerText());
 
             // Unset time limit for app.
             runWithShellPermission(
                     () -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
 
             mLauncher.goHome();
-            assertFalse("Toast is visible", getToast().hasLimit());
+            assertFalse("Toast is visible", getToast().getHasLimit());
         } finally {
             runWithShellPermission(
                     () -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index 2087016..9bc1c59 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -15,20 +15,18 @@
  */
 package com.android.quickstep;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Intent;
 import android.platform.test.annotations.PlatinumTest;
 
+import com.android.launcher3.tapl.Overview;
 import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask;
 import com.android.launcher3.tapl.OverviewTaskMenu;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
 
 import org.junit.Test;
 
@@ -70,39 +68,17 @@
 
     @Test
     public void testSplitTaskTapBothIconMenus() {
-        createAndLaunchASplitPair();
+        Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
 
-        OverviewTaskMenu taskMenu =
-                mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+        OverviewTaskMenu taskMenu = overview.getCurrentTask().tapMenu();
         assertTrue("App info item not appearing in expanded task menu.",
                 taskMenu.hasMenuItem("App info"));
         taskMenu.touchOutsideTaskMenuToDismiss();
 
-        OverviewTaskMenu splitMenu =
-                mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu(
+        OverviewTaskMenu splitMenu = overview.getCurrentTask().tapMenu(
                         OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT);
         assertTrue("App info item not appearing in expanded split task's menu.",
                 splitMenu.hasMenuItem("App info"));
         splitMenu.touchOutsideTaskMenuToDismiss();
     }
-
-    private void createAndLaunchASplitPair() {
-        clearAllRecentTasks();
-
-        startTestActivity(2);
-        startTestActivity(3);
-
-        if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
-            mLauncher.goHome().switchToOverview().getOverviewActions()
-                    .clickSplit()
-                    .getTestActivityTask(2)
-                    .open();
-        } else {
-            mLauncher.goHome().switchToOverview().getCurrentTask()
-                    .tapMenu()
-                    .tapSplitMenuItem()
-                    .getCurrentTask()
-                    .open();
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index c419cd2..a16811e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -23,7 +23,6 @@
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -31,8 +30,6 @@
 @RunWith(AndroidJUnit4.class)
 public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar {
 
-    //TODO(b/359277238): fix falling tests
-    @Ignore
     @Test
     @NavigationModeSwitch
     public void testTaskbarFillsWidth() {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 597227a..3e6436b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -266,9 +266,6 @@
         return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
     }
 
-    // Staging; will be promoted to presubmit if stable
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
@@ -293,9 +290,6 @@
         }
     }
 
-    // Staging; will be promoted to presubmit if stable
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
@@ -484,7 +478,8 @@
 //        assertTrue("Launcher internal state didn't remain in Overview",
 //                isInState(() -> LauncherState.OVERVIEW));
 //        overview.getCurrentTask().dismiss();
-//        executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
+//        executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple
+//        dismissals",
 //                (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
 //                        launcher)) <= 1)));
 
@@ -521,8 +516,6 @@
                 isInState(() -> LauncherState.NORMAL));
     }
 
-    //TODO(b/359277238): fix falling tests
-    @Ignore
     @Test
     @PortraitLandscape
     @TaskbarModeSwitch
@@ -595,7 +588,8 @@
         if (overview.hasTasks()) {
             currentTask = overview.getCurrentTask();
             assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home",
-                    currentTask.containsContentDescription("ExcludeFromRecents")
+                    currentTask.containsContentDescription(
+                            "ExcludeFromRecents")
                             || currentTask.containsContentDescription(null));
         } else {
             // Presumably the test started with 0 tasks and remains that way after going home.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 733ea4e..daa4ec3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -17,8 +17,6 @@
 
 
 import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -33,7 +31,7 @@
 import com.android.launcher3.tapl.Overview;
 import com.android.launcher3.tapl.Taskbar;
 import com.android.launcher3.tapl.TaskbarAppIcon;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
 import com.android.wm.shell.Flags;
 
 import org.junit.After;
@@ -110,9 +108,8 @@
         assumeTrue("App pairs feature is currently not enabled, no test needed",
                 Flags.enableAppPairs());
 
-        createAndLaunchASplitPair();
+        Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
 
-        Overview overview = mLauncher.goHome().switchToOverview();
         if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) {
             assertTrue("Save app pair menu item is missing",
                     overview.getCurrentTask()
@@ -156,24 +153,4 @@
         TaskbarAppIcon firstApp = taskbar.getAppIcon(firstAppName);
         firstApp.launchIntoSplitScreen();
     }
-
-    private void createAndLaunchASplitPair() {
-        clearAllRecentTasks();
-
-        startTestActivity(2);
-        startTestActivity(3);
-
-        if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
-            mLauncher.goHome().switchToOverview().getOverviewActions()
-                    .clickSplit()
-                    .getTestActivityTask(2)
-                    .open();
-        } else {
-            mLauncher.goHome().switchToOverview().getCurrentTask()
-                    .tapMenu()
-                    .tapSplitMenuItem()
-                    .getCurrentTask()
-                    .open();
-        }
-    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 2c23f86..710ad6f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -16,8 +16,6 @@
 
 package com.android.quickstep;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
 
 import static org.junit.Assert.assertNotNull;
@@ -32,8 +30,6 @@
 import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
 import com.android.launcher3.tapl.Workspace;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule;
-import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.After;
@@ -95,8 +91,6 @@
     @Test
     @PortraitLandscape
     @NavigationModeSwitch
-    @ScreenRecordRule.ScreenRecord // b/336606166
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/336606166
     public void switchToOverview() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 3a83ae3..28c8a4a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -59,8 +59,6 @@
 
     @Test
     public void startRecentsActivity_allowBackgroundLaunch() {
-        assumeTrue(TaskAnimationManager.ENABLE_SHELL_TRANSITIONS);
-
         final LauncherActivityInterface activityInterface = mock(LauncherActivityInterface.class);
         final GestureState gestureState = mock(GestureState.class);
         final RecentsAnimationCallbacks.RecentsAnimationListener listener =
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
new file mode 100644
index 0000000..82361aa
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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 androidx.test.uiautomator.By
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.launcher3.tapl.Overview
+import com.android.launcher3.tapl.OverviewTask
+import com.android.launcher3.ui.AbstractLauncherUiTest
+
+object SplitScreenTestUtils {
+
+    /** Creates 2 tasks and makes a split mode pair. Also asserts the accessibility labels. */
+    @JvmStatic
+    fun createAndLaunchASplitPairInOverview(launcher: LauncherInstrumentation): Overview {
+        clearAllRecentTasks(launcher)
+
+        AbstractLauncherUiTest.startTestActivity(2)
+        AbstractLauncherUiTest.startTestActivity(3)
+
+        val overView = launcher.goHome().switchToOverview()
+        if (launcher.isTablet && !launcher.isGridOnlyOverviewEnabled) {
+            overView.overviewActions.clickSplit().getTestActivityTask(2).open()
+        } else {
+            overView.currentTask.tapMenu().tapSplitMenuItem().currentTask.open()
+        }
+
+        val overviewWithSplitPair = launcher.goHome().switchToOverview()
+        val currentTask = overviewWithSplitPair.currentTask
+        currentTask.containsContentDescription(
+            By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(),
+            OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT
+        )
+        currentTask.containsContentDescription(
+            By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(),
+            OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT
+        )
+        return overviewWithSplitPair
+    }
+
+    private fun clearAllRecentTasks(launcher: LauncherInstrumentation) {
+        if (launcher.recentTasks.isNotEmpty()) {
+            launcher.goHome().switchToOverview().dismissAllTasks()
+        }
+    }
+}
diff --git a/res/color-night-v31/popup_color_background.xml b/res/color-night-v31/popup_color_background.xml
deleted file mode 100644
index 13ceaa0..0000000
--- a/res/color-night-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item
-        android:color="@android:color/system_neutral1_900"
-        android:lStar="12" />
-</selector>
diff --git a/res/color-v31/popup_color_background.xml b/res/color-v31/popup_color_background.xml
deleted file mode 100644
index 99155d8..0000000
--- a/res/color-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item
-        android:color="@android:color/system_neutral1_50"
-        android:lStar="94" />
-</selector>
diff --git a/res/color/popup_color_background.xml b/res/color/popup_color_background.xml
deleted file mode 100644
index e87e772..0000000
--- a/res/color/popup_color_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item android:color="?attr/popupColorBackground" />
-</selector>
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
index be4765a..39af989 100644
--- a/res/drawable/add_item_dialog_background.xml
+++ b/res/drawable/add_item_dialog_background.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
-    <solid android:color="?attr/materialColorSurfaceContainerHighest" />
+    <solid android:color="?attr/widgetPickerPrimarySurfaceColor" />
     <corners
         android:topLeftRadius="?android:attr/dialogCornerRadius"
         android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/res/drawable/bg_letter_list_text.xml b/res/drawable/bg_letter_list_text.xml
new file mode 100644
index 0000000..427702b
--- /dev/null
+++ b/res/drawable/bg_letter_list_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="?attr/materialColorSurfaceContainer" />
+    <corners android:radius="100dp"/>
+    <size
+        android:width="@dimen/bg_letter_list_text_size"
+        android:height="@dimen/bg_letter_list_text_size"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/popup_background.xml b/res/drawable/popup_background.xml
index 6eedecb..4ddd228 100644
--- a/res/drawable/popup_background.xml
+++ b/res/drawable/popup_background.xml
@@ -15,6 +15,6 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/popupColorBackground"/>
+    <solid android:color="?attr/materialColorSurfaceContainer"/>
     <corners android:radius="@dimen/dialogCornerRadius"/>
 </shape>
\ No newline at end of file
diff --git a/res/drawable/widget_picker_tabs_background.xml b/res/drawable/widget_picker_tabs_background.xml
index a874dd8..f6607b7 100644
--- a/res/drawable/widget_picker_tabs_background.xml
+++ b/res/drawable/widget_picker_tabs_background.xml
@@ -13,36 +13,39 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="@color/accent_ripple_color">
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetBottom="@dimen/widget_apps_tabs_vertical_padding"
+    android:insetTop="@dimen/widget_apps_tabs_vertical_padding">
+    <ripple
+        android:color="@color/accent_ripple_color">
 
-    <item android:id="@android:id/mask">
-        <shape android:shape="rectangle">
-            <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-            <solid android:color="@color/accent_ripple_color" />
-        </shape>
-    </item>
+        <item android:id="@android:id/mask">
+            <shape android:shape="rectangle">
+                <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+                <solid android:color="@color/accent_ripple_color" />
+            </shape>
+        </item>
 
-    <item>
-        <selector android:enterFadeDuration="100">
-            <item
-                android:id="@+id/unselected"
-                android:state_selected="false">
-                <shape android:shape="rectangle">
-                    <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-                    <solid android:color="?attr/widgetPickerTabBackgroundUnselected"/>
-                </shape>
-            </item>
+        <item>
+            <selector android:enterFadeDuration="100">
+                <item
+                    android:id="@+id/unselected"
+                    android:state_selected="false">
+                    <shape android:shape="rectangle">
+                        <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+                        <solid android:color="?attr/widgetPickerTabBackgroundUnselected" />
+                    </shape>
+                </item>
 
-            <item
-                android:id="@+id/selected"
-                android:state_selected="true">
-                <shape android:shape="rectangle">
-                    <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-                    <solid android:color="?attr/widgetPickerTabBackgroundSelected"/>
-                </shape>
-            </item>
-        </selector>
-    </item>
-
-</ripple>
\ No newline at end of file
+                <item
+                    android:id="@+id/selected"
+                    android:state_selected="true">
+                    <shape android:shape="rectangle">
+                        <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+                        <solid android:color="?attr/widgetPickerTabBackgroundSelected" />
+                    </shape>
+                </item>
+            </selector>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 0f1d933..7e16ca5 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -36,4 +36,17 @@
         android:layout_marginEnd="@dimen/fastscroll_end_margin"
         launcher:canThumbDetach="true" />
 
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/scroll_letter_layout"
+        android:layout_width="@dimen/fastscroll_width"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignTop="@+id/all_apps_header"
+        android:layout_marginTop="@dimen/all_apps_header_bottom_padding"
+        android:layout_marginEnd="@dimen/fastscroll_list_letter_end_margin"
+        android:clipToPadding="false"
+        android:outlineProvider="none"
+        />
 </merge>
\ No newline at end of file
diff --git a/res/layout/fast_scroller_letter_list_text_view.xml b/res/layout/fast_scroller_letter_list_text_view.xml
new file mode 100644
index 0000000..493b6fc
--- /dev/null
+++ b/res/layout/fast_scroller_letter_list_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<com.android.launcher3.allapps.LetterListTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/fastscroll_list_letter_size"
+    android:layout_height="@dimen/fastscroll_list_letter_size"
+    android:textSize="@dimen/fastscroll_list_letter_text_size"
+    android:importantForAccessibility="no"
+    android:gravity="center"
+    android:clickable="false">
+</com.android.launcher3.allapps.LetterListTextView>
\ No newline at end of file
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index a709fbc..83c8d6c 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -51,7 +51,7 @@
 
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
-        <com.android.launcher3.pageindicators.WorkspacePageIndicator
+        <com.android.launcher3.pageindicators.PageIndicatorDots
             android:id="@+id/page_indicator"
             android:layout_width="match_parent"
             android:layout_height="@dimen/workspace_page_indicator_height"
diff --git a/res/layout/page_indicator_dots.xml b/res/layout/page_indicator_dots.xml
deleted file mode 100644
index d5fe51e..0000000
--- a/res/layout/page_indicator_dots.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 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.
--->
-
-<com.android.launcher3.pageindicators.PageIndicatorDots xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/page_indicator"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/workspace_page_indicator_height"
-    android:layout_gravity="bottom | center_horizontal"
-    android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 8dc785a..622f0d6 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -104,7 +104,6 @@
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
                 android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
-                android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
                 android:layout_weight="1"
                 android:background="@drawable/widget_picker_tabs_background"
                 android:text="@string/widgets_full_sheet_personal_tab"
@@ -117,7 +116,6 @@
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
                 android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
-                android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
                 android:layout_weight="1"
                 android:background="@drawable/widget_picker_tabs_background"
                 android:text="@string/widgets_full_sheet_work_tab"
diff --git a/res/layout/widgets_two_pane_sheet_paged_view.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
index 1f41680..1cbd2ba 100644
--- a/res/layout/widgets_two_pane_sheet_paged_view.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -115,7 +115,6 @@
                     android:layout_width="0dp"
                     android:layout_height="match_parent"
                     android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
-                    android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
                     android:layout_weight="1"
                     android:background="@drawable/widget_picker_tabs_background"
                     android:text="@string/widgets_full_sheet_personal_tab"
@@ -128,7 +127,6 @@
                     android:layout_width="0dp"
                     android:layout_height="match_parent"
                     android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
-                    android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
                     android:layout_weight="1"
                     android:background="@drawable/widget_picker_tabs_background"
                     android:text="@string/widgets_full_sheet_work_tab"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 8b4b26a..490a7c2 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Borrel"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n program toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lees tuis-instellings en -kortpaaie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 03f62bf..7292eec 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"አረፋ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"አቋራጮችን ይጭናል"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"መተግበሪያው ያለተጠቃሚ ጣልቃ ገብነት አቋራጭ እንዲያክል ያስችለዋል።"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"የመነሻ ቅንብሮች እና አቋራጮችን ያነባል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 31ebd34..06fc0a8 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"فقاعة"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"تثبيت اختصارات"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"للسماح لتطبيق ما بإضافة اختصارات بدون تدخل المستخدم."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"الاطلاع على الإعدادات والاختصارات على الشاشة الرئيسية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index e2f4ecd..cd6e347 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্‌টো পিন কৰক"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"বাবল"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"শ্বৰ্টকাট ইনষ্টল কৰিব পাৰে"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ব্য়ৱহাৰকাৰীৰ হস্তক্ষেপ অবিহনেই কোনো এপক শ্বৰ্টকাটবোৰ যোগ কৰাৰ অনুমতি দিয়ে।"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"গৃহ স্ক্ৰীনত ছেটিং আৰু শ্বৰ্টকাটসমূহ পঢ়া"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 520295e..b8d660f 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Qabarcıq"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"qısayolları quraşdır"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tətbiqə istifadəçi müdaxiləsi olmadan qısayolları əlavə etməyə icazə verir."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Əsas səhifə ayarlarını və qısayollarını oxumaq"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 09ddf76..4d4764e 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"čitanje podešavanja i prečica na početnom ekranu"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 85792f7..641509e 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Бурбалка"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Стварэнне ярлыкоў"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дазваляе праграмам дадаваць ярлыкі без умяшання карыстальніка."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"счытваць налады і ярлыкі на галоўным экране"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index baf405d..3ce3c5f 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Балонче"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталиране на преки пътища"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Разрешава на приложението да добавя преки пътища без намеса на потребителя."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"четене на настройките и преките пътища на началния екран"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index a6bdde1..9b23590 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"বাবল"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"হোম স্ক্রিনে সেটিংস ও শর্টকাট পড়ুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 0de15da..4a34da7 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliraj prečice"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dopušta aplikaciji dodavanje prečica bez posredovanja korisnika."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"čita postavke na početnom ekranu i prečice"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 18753ba..c341ec7 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bombolla"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"llegir la configuració i les dreceres de la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e2e5ebf..d3512c9 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bublat"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalace zástupce"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Umožňuje aplikaci přidat zástupce bez zásahu uživatele."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"čtení nastavení a zkratek plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 31b6437..8aae860 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Boble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere genveje"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillader, at en app tilføjer genveje uden brugerens indgriben."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"læs indstillinger og genveje for startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 2abbf4c..374f5a1 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Verknüpfungen installieren"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ermöglicht einer App das Hinzufügen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Einstellungen und Verknüpfungen auf dem Startbildschirm lesen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index d4322b1..cafe86e 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Συννεφάκι"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ανάγνωση ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 33a3c4d..1b0722d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 33a3c4d..1b0722d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 33a3c4d..1b0722d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 793e5f2..ba1b0af 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación agregue accesos directos sin que el usuario intervenga."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"leer parámetros de configuración y accesos directos de la página principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 01b053c..ad12192 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"leer ajustes y accesos directos de la pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 231d0f7..96d0b2c 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Mull"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"avakuva seadete ja otseteede lugemine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 1c734b1..bc9b8c1 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Burbuila"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzeko baimena ematen die aplikazioei."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"irakurri hasierako pantailako ezarpenak eta lasterbideak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index a8a5491..c167194 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -24,7 +24,7 @@
     <string name="activity_not_found" msgid="8071924732094499514">"برنامه نصب نشده است."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"برنامه در دسترس نیست"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"برنامه بارگیری شده در حالت ایمن غیرفعال شد"</string>
-    <string name="safemode_widget_error" msgid="4863470563535682004">"ابزارک‌ها در حالت ایمن غیرفعال هستند"</string>
+    <string name="safemode_widget_error" msgid="4863470563535682004">"ابزاره‌ها در حالت ایمن غیرفعال هستند"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"میان‌بر دردسترس نیست"</string>
     <string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</string>
     <string name="set_default_home_app" msgid="5808906607627586381">"تنظیم <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> به‌عنوان برنامه صفحه اصلی پیش‌فرض در «تنظیمات»"</string>
@@ -36,40 +36,40 @@
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمی‌شود"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"برای استفاده از این جفت برنامه، دستگاه را باز کنید"</string>
     <string name="app_pair_not_available" msgid="3556767440808032031">"جفت برنامه دردسترس نیست"</string>
-    <string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابه‌جا کردن ابزارک، لمس کنید و نگه دارید."</string>
-    <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابه‌جا کردن ابزارک یا استفاده از کنش‌های سفارشی، دو تک‌ضرب بزنید و نگه دارید."</string>
+    <string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابه‌جا کردن ابزاره، لمس کنید و نگه دارید."</string>
+    <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابه‌جا کردن ابزاره یا استفاده از کنش‌های سفارشی، دو تک‌ضرب بزنید و نگه دارید."</string>
     <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"گزینه‌های بیشتر"</string>
     <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"نمایش همه ابزاره‌ها"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏%1$d عرض در %2$d طول"</string>
-    <string name="widget_preview_context_description" msgid="9045841361655787574">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>، %2$d عرض در %3$d ارتفاع"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ابزارک را لمس کنید و نگه دارید تا بتوانید آن را در صفحه اصلی حرکت دهید"</string>
+    <string name="widget_preview_context_description" msgid="9045841361655787574">"ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>، %2$d عرض در %3$d ارتفاع"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ابزاره را لمس کنید و نگه دارید تا بتوانید آن را در صفحه اصلی حرکت دهید"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"افزودن به صفحه اصلی"</string>
-    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g> به صفحه اصلی اضافه شد"</string>
+    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g> به صفحه اصلی اضافه شد"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"پیشنهادها"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ضروریات"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"اخبار و مجله"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"سرگرمی"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
-    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارک‌های <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینه‌ها در سمت راست"</string>
-    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‏# ابزارک}one{‏# ابزارک}other{‏# ابزارک}}"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزاره‌های <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، «جستجو» و گزینه‌ها در سمت راست"</string>
+    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‏# ابزاره}one{‏# ابزاره}other{‏# ابزاره}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‏# میان‌بر}one{‏# میان‌بر}other{‏# میان‌بر}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
-    <string name="widget_button_text" msgid="2880537293434387943">"ابزارک‌ها"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"ابزاره‌ها"</string>
     <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"جستجو"</string>
     <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"پاک کردن نوشتار از چارگوش جستجو"</string>
-    <string name="no_widgets_available" msgid="4337693382501046170">"ابزارک و میان‌بری دردسترس نیست"</string>
-    <string name="no_search_results" msgid="3787956167293097509">"هیچ ابزارک یا میان‌بری پیدا نشد"</string>
-    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ابزارک‌های شخصی"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"کار"</string>
+    <string name="no_widgets_available" msgid="4337693382501046170">"ابزاره و میان‌بری دردسترس نیست"</string>
+    <string name="no_search_results" msgid="3787956167293097509">"هیچ ابزاره یا میان‌بری پیدا نشد"</string>
+    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ابزاره‌های شخصی"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ابزاره‌های کاری"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"مکالمه‌ها"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشت‌برداری"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
-    <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، تک‌ضرب بزنید"</string>
-    <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزارک"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزاره، تک‌ضرب بزنید"</string>
+    <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزاره"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامه‌ها"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"درحال بارگیری برنامه‌‌ها…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"هیچ برنامه‌ای در مطابقت با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
@@ -92,16 +92,15 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"حبابک"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"نصب میان‌برها"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"به برنامه اجازه می‌دهد میان‌برها را بدون دخالت کاربر اضافه کند."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"خواندن تنظیمات و میان‌برهای صفحه اصلی"</string>
     <string name="permdesc_read_settings" msgid="4208061150510996676">"به برنامه اجازه می‌دهد تنظیمات و میان‌برهای صفحه اصلی را بخواند."</string>
     <string name="permlab_write_settings" msgid="4820028712156303762">"نوشتن تنظیمات و میان‌برهای صفحه اصلی"</string>
     <string name="permdesc_write_settings" msgid="726859348127868466">"به برنامه اجازه می‌دهد تنظیمات و میان‌برهای صفحه اصلی را تغییر دهد."</string>
-    <string name="gadget_error_text" msgid="740356548025791839">"ابزارک را نمی‌توان بار کرد"</string>
-    <string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزارک"</string>
+    <string name="gadget_error_text" msgid="740356548025791839">"ابزاره را نمی‌توان بار کرد"</string>
+    <string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزاره"</string>
     <string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تکمیل راه‌اندازی تک‌ضرب بزنید"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمی‌شود."</string>
     <string name="folder_hint_text" msgid="5174843001373488816">"ویرایش نام"</string>
@@ -147,8 +146,8 @@
     <string name="dialog_update_message" msgid="4176784553982226114">"برنامه برای این نماد به‌روز نشده است. می‌توانید آن را به‌صورت دستی به‌روز کنید تا میان‌بر دوباره فعال شود، یا نماد را بردارید."</string>
     <string name="dialog_update" msgid="2178028071796141234">"به‌روزرسانی"</string>
     <string name="dialog_remove" msgid="6510806469849709407">"برداشتن"</string>
-    <string name="widgets_list" msgid="796804551140113767">"فهرست ابزارک‌ها"</string>
-    <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارک‌ها بسته شد"</string>
+    <string name="widgets_list" msgid="796804551140113767">"فهرست ابزاره‌ها"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزاره‌ها بسته شد"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"افزودن به صفحه اصلی"</string>
     <string name="action_move_here" msgid="2170188780612570250">"انتقال مورد به اینجا"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"مورد به صفحه اصلی اضافه شد"</string>
@@ -170,7 +169,7 @@
     <string name="action_increase_height" msgid="459390020612501122">"افزایش ارتفاع"</string>
     <string name="action_decrease_width" msgid="1374549771083094654">"کاهش عرض"</string>
     <string name="action_decrease_height" msgid="282377193880900022">"کاهش ارتفاع"</string>
-    <string name="widget_resized" msgid="9130327887929620">"اندازه ابزارک به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
+    <string name="widget_resized" msgid="9130327887929620">"اندازه ابزاره به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"میان‌برها"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"رد کردن"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 0cf15f4..007d077 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Kupla"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"asenna pikakuvakkeita"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lukea aloitusnäytön asetuksia ja pikakuvakkeita"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 447909a..c443505 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bulle"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une appli d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 48c3bde..4f5d111 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -31,7 +31,7 @@
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
     <string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applis"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer une paire d\'applis"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Dépliez l\'appareil pour utiliser cette paire d\'applications"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bulle"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permettre à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 61a7e3d..ff7c029 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Burbulla"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ler a configuración e os atallos da pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index b85038c..872faef 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"બબલ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"શૉર્ટકટ ઇન્સ્ટૉલ કરો"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ ઉમેરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"હોમ સેટિંગ અને શૉર્ટકટ વાંચો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 1205515..a44b874 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्‍टॉल करें"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप पिन करें"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"बबल"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्‍टॉल करें"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ऐप को उपयोगकर्ता के हस्‍तक्षेप के बिना शॉर्टकट जोड़ने देती है."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रीन की सेटिंग और शॉर्टकट पढ़ने की अनुमति"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 1238172..d9f2072 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečaca"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji omogućuje dodavanje prečaca bez intervencije korisnika."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"čitati postavke i prečace početnog zaslona"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index acd4156..6bc8b70 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Buborék"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"kezdőképernyő beállításainak és parancsikonjainak olvasása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 2c020ad..69b320d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Ամպիկ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Դյուրանցումների տեղադրում"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Հավելվածին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 6586bb4..58a429f 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Balon"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"membaca setelan dan pintasan layar utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index f4593ec..95bd21f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Blaðra"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lesa stillingar og flýtileiðir heimaskjás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index a444d21..3c01cd4 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Fumetto"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Aggiunta di scorciatoie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"leggere le impostazioni e le scorciatoie nella schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 3a45b9f..f198166 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -63,7 +63,7 @@
     <string name="no_widgets_available" msgid="4337693382501046170">"אין ווידג\'טים או קיצורי דרך"</string>
     <string name="no_search_results" msgid="3787956167293097509">"לא נמצאו ווידג\'טים או קיצורי דרך"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ווידג\'טים אישיים"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"עבודה"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ווידג\'טים לעבודה"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"שיחות"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"בועה"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"התקנת קיצורי דרך"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"מאפשר לאפליקציה להוסיף קיצורי דרך ללא התערבות המשתמש."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"קריאת ההגדרות וקיצורי הדרך בדף הבית"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9dacea1..d2f9a97 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ふきだし"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ショートカットのインストール"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ユーザー操作なしでショートカットを追加することをアプリに許可します。"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ホームの設定とショートカットの読み取り"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 9e0e4a9..e67cc41 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ბუშტი"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"მალსახმობების დაყენება"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"აპისთვის მალსახმობების დამოუკიდებლად დამატების უფლების მიცემა."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 48f3478..d5ccae5 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Болжамды бекіту"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Қалқыма терезе"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"таңбаша орнату"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"негізгі экран параметрлері мен таңбашаларын оқу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 0044e6a..3c9135b 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការ​ព្យាករ"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ពពុះ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ដំឡើង​ផ្លូវកាត់"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​បន្ថែម​ផ្លូវកាត់​ ដោយ​មិន​ចាំបាច់​​អំពើ​ពី​អ្នក​ប្រើ។"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"អានការកំណត់ និងផ្លូវកាត់របស់អេក្រង់ដើម"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index f2d4e55..ab84833 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ಬಬಲ್"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಓದಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f3e5a3a..318cd00 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"풍선"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"바로가기 설치"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"앱이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"홈 설정 및 바로가기 읽기"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index e955666..856e2b2 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -39,7 +39,7 @@
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетти кое бербей басып туруп жылдырыңыз."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетти жылдыруу үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
     <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Дагы параметрлер"</string>
-    <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Бардык виджет-ди көрсөтүү"</string>
+    <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Виджеттин баарын көрсөтүү"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Туурасы: %1$d, бийиктиги: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Көбүкчө"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"үйдүн параметрлерин жана ыкчам баскычтарын окуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 78fe222..3d1a6c9 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ຟອງ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ຕິດຕັ້ງທາງລັດ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ອະນຸຍາດໃຫ້ແອັບຯ ເພີ່ມທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ອ່ານການຕັ້ງຄ່າໜ້າຫຼັກ ແລະ ທາງລັດ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4954848..4c9bd9b 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Debesėlis"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"įdiegti sparčiuosius klavišus"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Programai leidžiama pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"skaityti pagrindinio ekrano nustatymus ir sparčiuosius klavišus"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 49e9825..0a82705 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Burbulis"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalēt saīsnes"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ļauj lietotnei pievienot saīsnes, nejautājot lietotājam."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"sākuma ekrāna iestatījumu un saīšņu lasīšana"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 626a80e..887ca82 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Балонче"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"да чита поставки и кратенки на почетна страница"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index b777e0f..dda5679 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ബബിൾ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ഹോം ക്രമീകരണവും കുറുക്കുവഴികളും വായിക്കുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 6fe7967..49d71c2 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Бөмбөлөг"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"товчлол суулгах"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг нэмэж чадна"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"нүүрний тохиргоо болон товчлолыг унших"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 22d789b..fdf864a 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"बबल"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्टॉल करा"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"होम सेटिंग्ज आणि शॉर्टकट वाचा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 9320e45..b86f657 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -63,7 +63,7 @@
     <string name="no_widgets_available" msgid="4337693382501046170">"Widget dan pintasan tidak tersedia"</string>
     <string name="no_search_results" msgid="3787956167293097509">"Tiada widget atau pintasan yang dijumpai"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Peribadi"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Tempat kerja"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Perbualan"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Gelembung"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"membaca tetapan dan pintasan skrin utama"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 599c9a1..7e8fd14 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ပူဖောင်းကွက်"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ဖြတ်လမ်းလင့်ခ်များ ထည့်သွင်းခြင်း"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ပင်မဆက်တင်နှင့် ဖြတ်လမ်းလင့်ခ်များ ဖတ်ခြင်း"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 11b076c..2a6611f 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Boble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere snarveier"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Gir apper tillatelse til å legge til snarveier uten innblanding fra brukeren."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lese startsideinnstillinger og -snarveier"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index add65ee..fa2e59b 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"बबल"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रिनका सेटिङ र सर्टकटहरू रिड गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index c2bc5e0..9271b96 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Voorspelling vastzetten"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubbel"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 01c6dfc..98d52de 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ବବଲ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ସର୍ଟକଟ୍‍ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ୟୁଜରଙ୍କ ବିନା ହସ୍ତକ୍ଷେପରେ ଶର୍ଟକଟ୍‌ ଯୋଡ଼ିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ହୋମ ସେଟିଂସ ଏବଂ ସର୍ଟକଟଗୁଡ଼ିକୁ ପଢ଼ନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index dce05ae..782979e 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -63,7 +63,7 @@
     <string name="no_widgets_available" msgid="4337693382501046170">"ਵਿਜੇਟ ਜਾਂ ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
     <string name="no_search_results" msgid="3787956167293097509">"ਕੋਈ ਵੀ ਵਿਜੇਟ ਜਾਂ ਸ਼ਾਰਟਕੱਟ ਨਹੀਂ ਮਿਲਿਆ"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ਨਿੱਜੀ"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕਾਰਜ-ਸਥਾਨ"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕੰਮ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ਗੱਲਾਂਬਾਤਾਂ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"ਬਬਲ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਵਰਤੋਂਕਾਰ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index fae07369..71e569c 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Dymek"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalowanie skrótów"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pozwala aplikacji dodawać skróty bez interwencji użytkownika."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Odczytuje ustawienia i skróty na ekranie głównym"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 69b63cf..1c44d9b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Balão"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma app adicionar atalhos sem a intervenção do utilizador."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ler definições e atalhos do ecrã Principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index f4ee373..3f44591 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Balão"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ler configurações e atalhos da tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 5293657..b37d93b 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalează"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Balon"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalează comenzi rapide"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite unei aplicații să adauge comenzi rapide fără intervenția utilizatorului."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"citește setările și comenzile rapide de pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 0e8faa1..321bf37 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -47,7 +47,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Нажмите на виджет и удерживайте его, чтобы переместить в нужное место на главном экране."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Добавить на главный экран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" добавлен на главный экран"</string>
-    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Подсказки"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Рекомендованные"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основное"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и журналы"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Подсказка"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Создание ярлыков"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Приложение сможет самостоятельно добавлять ярлыки."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Доступ к данным о настройках и ярлыках на главном экране"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 9db82a7..91c818a 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"බුබුළ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"මුල් පිටු සැකසීම් සහ කෙටි මං කියවන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5007a7f..eaae7c0 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -39,7 +39,7 @@
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
     <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Ďalšie možnosti"</string>
-    <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Zobrazovať všetky miniap."</string>
+    <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Zobrazovať všetky miniaplikácie"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
@@ -58,12 +58,12 @@
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikácie"</string>
-    <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Vyhľadajte"</string>
+    <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Vyhľadávanie"</string>
     <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Vymazať text z vyhľadávacieho poľa"</string>
     <string name="no_widgets_available" msgid="4337693382501046170">"Miniaplikácie a odkazy nie sú k dispozícii"</string>
     <string name="no_search_results" msgid="3787956167293097509">"Nenašli sa žiadne miniaplikácie ani odkazy"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Osobné"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Práca"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Pracovné"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzácie"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bublina"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"inštalácia odkazov"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Povoľuje aplikácii pridať odkazy bez zásahu používateľa."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"čítanie nastavení a odkazov plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index ab2eff3..dccf2f1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Mehurček"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"branje nastavitev in bližnjic na začetnem zaslonu"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index a61cd6d..84484e8 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Flluskë"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalimi i shkurtoreve"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 621046f..64383f2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Облачић"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"читање подешавања и пречица на почетном екрану"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 812cbd7..47aed86 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -62,7 +62,7 @@
     <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Rensa texten från sökrutan"</string>
     <string name="no_widgets_available" msgid="4337693382501046170">"Widgetar och genvägar är inte tillgängliga"</string>
     <string name="no_search_results" msgid="3787956167293097509">"Inga widgetar eller genvägar hittades"</string>
-    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Privata"</string>
+    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Privat"</string>
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbete"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konversationer"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubbla"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installera genvägar"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillåter att en app lägger till genvägar utan åtgärd från användaren."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"läsa inställningar och genvägar på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5464af3..5eadd1d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Kiputo"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kuweka njia za mkato"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Huruhusu programu kuongeza njia za mkato bila mtumiaji kuingilia kati."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"kusoma mipangilio ya skrini ya kwanza na njia za mkato"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 29ca948..d84485a 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்டதைப் பின் செய்"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"குமிழ்"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"முகப்புத் திரையின் அமைப்புகளையும் ஷார்ட்கட்களையும் படித்தல்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 038f6b7..8487e96 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్‌స్టాల్ చేయండి"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"బబుల్"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"షార్ట్‌కట్‌లను ఇన్‌స్టాల్ చేయడం"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా షార్ట్‌కట్‌లను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"హోమ్ సెట్టింగ్‌లు, షార్ట్‌కట్‌లను చదవండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 72684cd..71f4d15 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"บับเบิล"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ติดตั้งทางลัด"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"อนุญาตให้แอปเพิ่มทางลัดโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"อ่านการตั้งค่าและทางลัดในหน้าแรก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ec265c7..7cf6a44 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"basahin ang mga setting at shortcut ng home"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index dd4dab6..d55181c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Balon"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ana ekran ayarlarını ve kısayollarını oku"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 7048517..b5c1c70 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Повідомлення"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"створення ярликів"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозволяє програмі самостійно додавати ярлики."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"читати налаштування та ярлики головного екрана"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 8460f73..6fa76dd 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"بلبلہ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index be02e01..21a8145 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Pufaklar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"Bosh ekrandagi sozlamalar va yorliqlarni koʻrish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 3d8b815..b0bac73 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Không gợi ý ứng dụng"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Bong bóng"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"cài đặt lối tắt"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"đọc lối tắt và các chế độ cài đặt trên màn hình chính"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 12a3a70..112b945 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要推荐此应用"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"气泡框"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安装快捷方式"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允许应用自行添加快捷方式。"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"读取主屏幕设置和快捷方式"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index c82a320..e63093e 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"氣泡"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需使用者許可也可新增捷徑。"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 714fc24..25f9703 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要建議此應用程式"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"泡泡"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式自動新增捷徑。"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index a84b1fb..ec1f941 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -92,8 +92,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
-    <!-- no translation found for bubble (3072951361014076670) -->
-    <skip />
+    <string name="bubble" msgid="3072951361014076670">"Ibhamuza"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"faka izinqamuleli"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ivumela uhlelo lokusebenza ukufaka izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"funda amasethingi wasekhaya nezinqamuleli"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 6151b5f..57c9bc7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -25,7 +25,6 @@
     <attr name="popupColorPrimary" format="color" />
     <attr name="popupColorSecondary" format="color" />
     <attr name="popupColorTertiary" format="color" />
-    <attr name="popupColorBackground" format="color" />
     <attr name="popupTextColor" format="color" />
     <attr name="popupShadeFirst" format="color" />
     <attr name="popupShadeSecond" format="color" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5e1d8a5..f8c075f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -81,6 +81,11 @@
     <dimen name="fastscroll_popup_text_size">32dp</dimen>
     <dimen name="fastscroll_popup_margin">19dp</dimen>
 
+    <dimen name="fastscroll_list_letter_size">5dp</dimen>
+    <dimen name="fastscroll_list_letter_text_size">14sp</dimen>
+    <dimen name="fastscroll_list_letter_end_margin">-10dp</dimen>
+    <dimen name="bg_letter_list_text_size">20sp</dimen>
+
     <!--
       Fast scroller draws the content horizontally centered. The end of the track should be
       aligned at the end of the container.
@@ -306,7 +311,7 @@
     <dimen name="blur_size_medium_outline">2dp</dimen>
     <dimen name="blur_size_click_shadow">4dp</dimen>
     <dimen name="click_shadow_high_shift">2dp</dimen>
-    <dimen name="app_title_icon_shadow_inset">1dp</dimen>
+    <dimen name="app_title_icon_shadow_inset">0.5dp</dimen>
 
     <!-- Pending widget -->
     <dimen name="pending_widget_min_padding">8dp</dimen>
@@ -456,6 +461,7 @@
     <!-- Overview placeholder to compile in Launcher3 without Quickstep -->
     <dimen name="task_thumbnail_icon_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
+    <dimen name="task_thumbnail_splash_icon_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
     <dimen name="task_thumbnail_icon_menu_drawable_touch_size">0dp</dimen>
     <dimen name="task_menu_edge_padding">0dp</dimen>
@@ -482,8 +488,6 @@
     <dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
     <dimen name="split_instructions_start_margin_cancel">8dp</dimen>
-    <dimen name="split_divider_handle_region_width">96dp</dimen>
-    <dimen name="split_divider_handle_region_height">48dp</dimen>
 
     <dimen name="focus_outline_radius">16dp</dimen>
     <dimen name="focus_inner_outline_radius">14dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ee7ed26..728c523 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -77,6 +77,10 @@
         <item name="materialColorError">@color/system_error_light</item>
     </style>
 
+    <style name="DynamicColorsBaseLauncherTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
 
     <style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
@@ -86,7 +90,6 @@
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_light</item>
         <item name="popupColorTertiary">@color/popup_color_tertiary_light</item>
-        <item name="popupColorBackground">#EFEDED</item>
         <item name="popupTextColor">@color/system_on_surface_light</item>
         <item name="popupShadeFirst">@color/popup_shade_first_light</item>
         <item name="popupShadeSecond">@color/popup_shade_second_light</item>
@@ -161,7 +164,6 @@
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
         <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
-        <item name="popupColorBackground">#1F2020</item>
         <item name="popupTextColor">@color/system_on_surface_dark</item>
         <item name="popupNotificationDotColor">@color/popup_notification_dot_dark</item>
         <item name="popupShadeFirst">@color/popup_shade_first_dark</item>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index d3ee364..76c0f90 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -74,7 +74,8 @@
             TYPE_TASKBAR_ALL_APPS,
             TYPE_ADD_TO_HOME_CONFIRMATION,
             TYPE_TASKBAR_OVERLAY_PROXY,
-            TYPE_TASKBAR_PINNING_POPUP
+            TYPE_TASKBAR_PINNING_POPUP,
+            TYPE_PIN_IME_POPUP
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FloatingViewType {}
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index ef56246..b51e850 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -37,8 +37,6 @@
 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
 import com.android.launcher3.celllayout.CellPosMapper.CellPos;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.debug.TestEvent;
-import com.android.launcher3.debug.TestEventEmitter;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.logging.InstanceId;
@@ -223,9 +221,6 @@
         dl.addView(frame);
         frame.mIsOpen = true;
         frame.post(() -> frame.snapToWidget(false));
-        TestEventEmitter.INSTANCE.get(widget.getContext()).sendEvent(
-                TestEvent.RESIZE_FRAME_SHOWING
-        );
     }
 
     private void setCornerRadiusFromWidget() {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 633091d..fec94fe 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -110,11 +110,6 @@
     public static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 4;
 
     /**
-     * State flag indicating if the user will be active shortly.
-     */
-    public static final int ACTIVITY_STATE_USER_WILL_BE_ACTIVE = 1 << 5;
-
-    /**
      * State flag indicating that a state transition is in progress
      */
     public static final int ACTIVITY_STATE_TRANSITION_ACTIVE = 1 << 6;
@@ -316,7 +311,6 @@
      */
     public void setResumed() {
         addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
-        removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
     }
 
     public boolean isUserActive() {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 1eccbff..8121e53 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -89,7 +89,7 @@
 import com.android.launcher3.util.ShortcutUtil;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
 
 import java.text.NumberFormat;
 import java.util.HashMap;
@@ -101,7 +101,7 @@
  * too aggressive.
  */
 public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
-        IconLabelDotView, DraggableView, Reorderable {
+        FloatingIconViewCompanion, DraggableView, Reorderable {
 
     public static final String TAG = "BubbleTextView";
 
@@ -176,7 +176,7 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mSkipUserBadge = false;
     @ViewDebug.ExportedProperty(category = "launcher")
-    private boolean mIsIconVisible = true;
+    protected boolean mIsIconVisible = true;
     @ViewDebug.ExportedProperty(category = "launcher")
     private int mTextColor;
     @ViewDebug.ExportedProperty(category = "launcher")
@@ -1043,12 +1043,11 @@
     /** Applies the given progress level to the this icon's progress bar. */
     @Nullable
     public PreloadIconDrawable applyProgressLevel() {
-        if (!(getTag() instanceof ItemInfoWithIcon)
+        if (!(getTag() instanceof ItemInfoWithIcon info)
                 || ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
             return null;
         }
 
-        ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
         int progressLevel = info.getProgressLevel();
         if (progressLevel >= 100) {
             setContentDescription(info.contentDescription != null
@@ -1068,6 +1067,10 @@
             } else {
                 preloadIconDrawable = makePreloadIcon();
                 setIcon(preloadIconDrawable);
+                if (info.isArchived() && Flags.useNewIconForArchivedApps()) {
+                    // reapply text without cloud icon as soon as unarchiving is triggered
+                    applyLabel(info);
+                }
             }
             return preloadIconDrawable;
         }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 7e9e864..ee72c22 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -86,7 +86,7 @@
 
 public class CellLayout extends ViewGroup {
     private static final String TAG = "CellLayout";
-    private static final boolean LOGD = false;
+    private static final boolean LOGD = true;
 
     /** The color of the "leave-behind" shape when a folder is opened from Hotseat. */
     private static final int FOLDER_LEAVE_BEHIND_COLOR = Color.argb(160, 245, 245, 245);
@@ -166,6 +166,7 @@
     private final int[] mDragCellSpan = new int[2];
 
     private boolean mDragging = false;
+    public boolean mHasOnLayoutBeenCalled = false;
 
     private final TimeInterpolator mEaseOutInterpolator;
     protected final ShortcutAndWidgetContainer mShortcutsAndWidgets;
@@ -1009,6 +1010,7 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
         int left = getPaddingLeft();
         left += (int) Math.ceil(getUnusedHorizontalSpace() / 2f);
         int right = r - l - getPaddingRight();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 5cbf6fb..8ae6d73 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -316,6 +316,74 @@
     // DragController
     public int flingToDeleteThresholdVelocity;
 
+    /** Used only as an alternative to mocking when null values cannot be used. */
+    @VisibleForTesting
+    public DeviceProfile() {
+        inv = null;
+        mInfo = null;
+        mMetrics = null;
+        mIconSizeSteps = null;
+        isTablet = false;
+        isPhone = false;
+        transposeLayoutWithOrientation = false;
+        isMultiDisplay = false;
+        isTwoPanels = false;
+        isPredictiveBackSwipe = false;
+        isQsbInline = false;
+        isLandscape = false;
+        isMultiWindowMode = false;
+        isGestureMode = false;
+        isLeftRightSplit = false;
+        windowX = 0;
+        windowY = 0;
+        widthPx = 0;
+        heightPx = 0;
+        availableWidthPx = 0;
+        availableHeightPx = 0;
+        rotationHint = 0;
+        aspectRatio = 1;
+        mIsScalableGrid = false;
+        mTypeIndex = 0;
+        mIsResponsiveGrid = false;
+        desiredWorkspaceHorizontalMarginOriginalPx = 0;
+        edgeMarginPx = 0;
+        workspaceContentScale = 0;
+        workspaceSpringLoadedMinNextPageVisiblePx = 0;
+        extraSpace = 0;
+        workspacePageIndicatorHeight = 0;
+        mWorkspacePageIndicatorOverlapWorkspace = 0;
+        numFolderRows = 0;
+        numFolderColumns = 0;
+        folderLabelTextScale = 0;
+        areNavButtonsInline = false;
+        mHotseatBarEdgePaddingPx = 0;
+        mHotseatBarWorkspaceSpacePx = 0;
+        hotseatQsbWidth = 0;
+        hotseatQsbHeight = 0;
+        hotseatQsbVisualHeight = 0;
+        hotseatQsbShadowHeight = 0;
+        hotseatBorderSpace = 0;
+        mMinHotseatIconSpacePx = 0;
+        mMinHotseatQsbWidthPx = 0;
+        mMaxHotseatIconSpacePx = 0;
+        inlineNavButtonsEndSpacingPx = 0;
+        mBubbleBarSpaceThresholdPx = 0;
+        numShownAllAppsColumns = 0;
+        overviewActionsHeight = 0;
+        overviewActionsTopMarginPx = 0;
+        overviewActionsButtonSpacing = 0;
+        mViewScaleProvider = null;
+        mDotRendererWorkSpace = null;
+        mDotRendererAllApps = null;
+        taskbarHeight = 0;
+        stashedTaskbarHeight = 0;
+        taskbarBottomMargin = 0;
+        taskbarIconSize = 0;
+        mTransientTaskbarClaimedSpace = 0;
+        startAlignTaskbar = false;
+        isTransientTaskbar = false;
+    }
+
     /** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */
     DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
             SparseArray<DotRenderer> dotRendererCache, boolean isMultiWindowMode,
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index de1748b..6622e11 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -25,6 +25,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -54,9 +55,11 @@
         super(context, attrs, defStyleAttr);
     }
 
-    public void bindFastScrollbar(RecyclerViewFastScroller scrollbar) {
+    public void bindFastScrollbar(RecyclerViewFastScroller scrollbar,
+            RecyclerViewFastScroller.FastScrollerLocation location) {
         mScrollbar = scrollbar;
         mScrollbar.setRecyclerView(this);
+        mScrollbar.setFastScrollerLocation(location);
         onUpdateScrollbar(0);
     }
 
@@ -163,6 +166,13 @@
     public abstract void onUpdateScrollbar(int dy);
 
     /**
+     * Return the fast scroll letter list view in the A-Z list.
+     */
+    public ConstraintLayout getLetterList() {
+        return null;
+    }
+
+    /**
      * <p>Override in each subclass of this base class.
      */
     public void onFastScrollCompleted() {}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fac372b..bafb528 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -135,14 +135,12 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
-import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MotionEvent;
 import android.view.View;
@@ -214,7 +212,6 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.pm.PinRequestHelper;
 import com.android.launcher3.popup.ArrowPopup;
 import com.android.launcher3.popup.PopupDataProvider;
@@ -438,6 +435,10 @@
         mIsColdStartupAfterReboot = sIsNewProcess
             && !LockedUserState.get(this).isUserUnlockedAtLauncherStartup();
         if (mIsColdStartupAfterReboot) {
+            /*
+             * This trace is used to calculate the time from create to the point that icons are
+             * visible.
+             */
             Trace.beginAsyncSection(
                     COLD_STARTUP_TRACE_METHOD_NAME, COLD_STARTUP_TRACE_COOKIE);
         }
@@ -1410,15 +1411,6 @@
                 this, R.attr.isWorkspaceDarkText) ? Color.BLACK : Color.WHITE);
     }
 
-    @Override
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-        if (WorkspacePageIndicator.class.getName().equals(name)) {
-            return LayoutInflater.from(context).inflate(R.layout.page_indicator_dots,
-                    (ViewGroup) parent, false);
-        }
-        return super.onCreateView(parent, name, context, attrs);
-    }
-
     /**
      * Add a shortcut to the workspace or to a Folder.
      *
@@ -2396,10 +2388,6 @@
                     .logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
                     .log()
                     .reset();
-            if (mIsColdStartupAfterReboot) {
-                Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
-                        COLD_STARTUP_TRACE_COOKIE);
-            }
         });
     }
 
@@ -2408,6 +2396,10 @@
             RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
         mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
                 workspaceItemCount, isBindSync);
+        if (mIsColdStartupAfterReboot) {
+            Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
+                    COLD_STARTUP_TRACE_COOKIE);
+        }
     }
 
     /**
@@ -2701,6 +2693,20 @@
         writer.println(prefix + "\tmAppWidgetHolder.isListening: "
                 + mAppWidgetHolder.isListening());
 
+        // b/349929393
+        // The only way to reproduce this bug is to ensure that onLayout never gets called. This
+        // theoretically is impossible, so these logs are being added to test if that actually is
+        // what is happening.
+        writer.println(prefix + "\tmWorkspace.mHasOnLayoutBeenCalled="
+                + mWorkspace.mHasOnLayoutBeenCalled);
+        for (int i = 0; i < mWorkspace.getPageCount(); i++) {
+            CellLayout cellLayout = (CellLayout) mWorkspace.getPageAt(i);
+            writer.println(prefix + "\tcellLayout." + i + ".mHasOnLayoutBeenCalled="
+                    + cellLayout.mHasOnLayoutBeenCalled);
+            writer.println(prefix + "\tshortcutAndWidgetContainer." + i + ".mHasOnLayoutBeenCalled="
+                    + cellLayout.getShortcutsAndWidgets().mHasOnLayoutBeenCalled);
+        }
+
         // Extra logging for general debugging
         mDragLayer.dump(prefix, writer);
         mStateManager.dump(prefix, writer);
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 40873be..8969b60 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -17,14 +17,23 @@
 
 import android.app.Application;
 
+import com.android.launcher3.dagger.DaggerLauncherAppComponent;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+
 /**
  * Main application class for Launcher
  */
 public class LauncherApplication extends Application {
 
+    private LauncherBaseAppComponent mAppComponent;
     @Override
     public void onCreate() {
         super.onCreate();
         MainProcessInitializer.initialize(this);
+        mAppComponent = DaggerLauncherAppComponent.builder().build();
+    }
+
+    public LauncherBaseAppComponent getAppComponent() {
+        return mAppComponent;
     }
 }
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index d2c3c78..a8733f2 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -64,6 +64,7 @@
 
     private final ActivityContext mActivity;
     private boolean mInvertIfRtl = false;
+    public boolean mHasOnLayoutBeenCalled = false;
 
     @Nullable
     private TranslationProvider mTranslationProvider = null;
@@ -201,6 +202,7 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         Trace.beginSection("ShortcutAndWidgetConteiner#onLayout");
+        mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2995e8a..255260e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -235,6 +235,7 @@
     boolean mChildrenLayersEnabled = true;
 
     private boolean mStripScreensOnPageStopMoving = false;
+    public boolean mHasOnLayoutBeenCalled = false;
 
     private boolean mWorkspaceFadeInAdjacentScreens;
 
@@ -1445,6 +1446,7 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
         if (mUnlockWallpaperFromDefaultPageOnLayout) {
             mWallpaperOffset.setLockToDefaultPage(false);
             mUnlockWallpaperFromDefaultPageOnLayout = false;
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 227ac2b..cc4724c 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -29,6 +29,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -65,6 +66,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
+import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -168,6 +170,7 @@
     protected FloatingHeaderView mHeader;
     protected View mBottomSheetBackground;
     protected RecyclerViewFastScroller mFastScroller;
+    private ConstraintLayout mFastScrollLetterLayout;
 
     /**
      * View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}.
@@ -282,6 +285,13 @@
         mSearchRecyclerView = findViewById(R.id.search_results_list_view);
         mFastScroller = findViewById(R.id.fast_scroller);
         mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
+        mFastScrollLetterLayout = findViewById(R.id.scroll_letter_layout);
+        if (Flags.letterFastScroller()) {
+            // Set clip children to false otherwise the scroller letters will be clipped.
+            setClipChildren(false);
+        } else {
+            setClipChildren(true);
+        }
 
         mSearchContainer = inflateSearchBar();
         if (!isSearchBarFloating()) {
@@ -563,7 +573,8 @@
             mActivityContext.hideKeyboard();
         }
         if (mAH.get(currentActivePage).mRecyclerView != null) {
-            mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller);
+            mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller,
+                    ALL_APPS_SCROLLER);
         }
         // Header keeps track of active recycler view to properly render header protection.
         mHeader.setActiveRV(currentActivePage);
@@ -1500,6 +1511,10 @@
         }
     }
 
+    ConstraintLayout getFastScrollerLetterList() {
+        return mFastScrollLetterLayout;
+    }
+
     /**
      * redraws header protection
      */
@@ -1567,7 +1582,7 @@
         void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
             mAppsList.updateItemFilter(matcher);
             mRecyclerView = (AllAppsRecyclerView) rv;
-            mRecyclerView.bindFastScrollbar(mFastScroller);
+            mRecyclerView.bindFastScrollbar(mFastScroller, ALL_APPS_SCROLLER);
             mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
             mRecyclerView.setApps(mAppsList);
             mRecyclerView.setLayoutManager(mLayoutManager);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 2a47222..ae45a35 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,6 +15,9 @@
  */
 package com.android.launcher3.allapps;
 
+import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
+import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
+
 import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo;
@@ -36,22 +39,29 @@
 import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
 import androidx.core.util.Consumer;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.views.ActivityContext;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -66,6 +76,7 @@
     protected final int mNumAppsPerRow;
     private final AllAppsFastScrollHelper mFastScrollHelper;
     private int mCumulativeVerticalScroll;
+    private ConstraintLayout mLetterList;
 
     protected AlphabeticalAppsList<?> mApps;
 
@@ -238,6 +249,9 @@
             return;
         }
 
+        if (Flags.letterFastScroller() && !mScrollbar.isDraggingThumb()) {
+            setLettersToScrollLayout(mApps.getFastScrollerSections());
+        }
         // Only show the scrollbar if there is height to be scrolled
         int availableScrollBarHeight = getAvailableScrollBarHeight();
         int availableScrollHeight = getAvailableScrollHeight();
@@ -319,6 +333,80 @@
         return false;
     }
 
+    public void setLettersToScrollLayout(
+            List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections) {
+        if (mLetterList != null) {
+            mLetterList.removeAllViews();
+        }
+        Context context = getContext();
+        ActivityAllAppsContainerView<?> allAppsContainerView =
+                ActivityContext.lookupContext(context).getAppsView();
+        mLetterList = allAppsContainerView.getFastScrollerLetterList();
+        mLetterList.setPadding(0, getScrollBarTop(), 0, getScrollBarMarginBottom());
+        List<LetterListTextView> textViews = new ArrayList<>();
+        for (int i = 0; i < fastScrollSections.size(); i++) {
+            AlphabeticalAppsList.FastScrollSectionInfo sectionInfo = fastScrollSections.get(i);
+            LetterListTextView textView =
+                    (LetterListTextView) LayoutInflater.from(context).inflate(
+                            R.layout.fast_scroller_letter_list_text_view, mLetterList, false);
+            int viewId = View.generateViewId();
+            textView.setId(viewId);
+            sectionInfo.setId(viewId);
+            textView.setText(sectionInfo.sectionName);
+            if (i == fastScrollSections.size() - 1) {
+                // The last section info is just a duplicate so that user can scroll to the bottom.
+                textView.setVisibility(INVISIBLE);
+            }
+            ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
+                    MATCH_CONSTRAINT, WRAP_CONTENT);
+            lp.dimensionRatio = "v,1:1";
+            textView.setLayoutParams(lp);
+            textViews.add(textView);
+            mLetterList.addView(textView);
+        }
+        // Need to add an extra textview to be aligned.
+        LetterListTextView lastLetterListTextView = new LetterListTextView(context);
+        int currentId = View.generateViewId();
+        lastLetterListTextView.setId(currentId);
+        lastLetterListTextView.setVisibility(INVISIBLE);
+        textViews.add(lastLetterListTextView);
+        mLetterList.addView(lastLetterListTextView);
+        constraintTextViewsVertically(mLetterList, textViews);
+        mLetterList.setVisibility(VISIBLE);
+    }
+
+    private void constraintTextViewsVertically(ConstraintLayout constraintLayout,
+            List<LetterListTextView> textViews) {
+        ConstraintSet chain = new ConstraintSet();
+        chain.clone(constraintLayout);
+        for (int i = 0; i < textViews.size(); i++) {
+            LetterListTextView currentView = textViews.get(i);
+            if (i == 0) {
+                chain.connect(currentView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID,
+                        ConstraintSet.TOP);
+            } else {
+                chain.connect(currentView.getId(), ConstraintSet.TOP, textViews.get(i-1).getId(),
+                        ConstraintSet.BOTTOM);
+            }
+            chain.connect(currentView.getId(), ConstraintSet.START, constraintLayout.getId(),
+                    ConstraintSet.START);
+            chain.connect(currentView.getId(), ConstraintSet.END, constraintLayout.getId(),
+                    ConstraintSet.END);
+        }
+        int[] viewIds = textViews.stream().mapToInt(TextView::getId).toArray();
+        float[] weights = new float[textViews.size()];
+        Arrays.fill(weights,1); // fill with 1 for equal weights
+        chain.createVerticalChain(constraintLayout.getId(), ConstraintSet.TOP,
+                constraintLayout.getId(), ConstraintSet.BOTTOM, viewIds, weights,
+                ConstraintSet.CHAIN_SPREAD);
+        chain.applyTo(constraintLayout);
+    }
+
+    @Override
+    public ConstraintLayout getLetterList() {
+        return mLetterList;
+    }
+
     private void logCumulativeVerticalScroll() {
         ActivityContext context = ActivityContext.lookupContext(getContext());
         StatsLogManager mgr = context.getStatsLogManager();
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 1b0ad04..742648e 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -37,7 +37,6 @@
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.util.FloatProperty;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
@@ -52,7 +51,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.PropertySetter;
@@ -359,22 +357,6 @@
             });
         }
 
-        if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.isUserControlled()
-                && Utilities.ATLEAST_S) {
-            if (toState == ALL_APPS) {
-                builder.addOnFrameListener(
-                        new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
-                                SWIPE_DRAG_COMMIT_THRESHOLD, 1));
-            } else {
-                builder.addOnFrameListener(
-                        new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
-                                0, SWIPE_DRAG_COMMIT_THRESHOLD));
-            }
-            builder.addEndListener((unused) -> {
-                mVibratorWrapper.cancelVibrate();
-            });
-        }
-
         float targetProgress = toState.getVerticalProgress(mLauncher);
         if (Float.compare(mProgress, targetProgress) == 0) {
             setAlphas(toState, config, builder);
@@ -391,8 +373,7 @@
 
         setAlphas(toState, config, builder);
         // This controls both haptics for tapping on QSB and going to all apps.
-        if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL) &&
-                !FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get()) {
+        if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
             mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
         }
@@ -445,45 +426,4 @@
     public void setShiftRange(float shiftRange) {
         mShiftRange = shiftRange;
     }
-
-    /**
-     * This VibrationAnimatorUpdateListener class takes in four parameters, a controller, start
-     * threshold, end threshold, and a Vibrator wrapper. We use the progress given by the controller
-     * as it gives an accurate progress that dictates where the vibrator should vibrate.
-     * Note: once the user begins a gesture and does the commit haptic, there should not be anymore
-     * haptics played for that gesture.
-     */
-    private static class VibrationAnimatorUpdateListener implements
-            ValueAnimator.AnimatorUpdateListener {
-        private final VibratorWrapper mVibratorWrapper;
-        private final AllAppsTransitionController mController;
-        private final float mStartThreshold;
-        private final float mEndThreshold;
-        private boolean mHasCommitted;
-
-        VibrationAnimatorUpdateListener(AllAppsTransitionController controller,
-                                        VibratorWrapper vibratorWrapper, float startThreshold,
-                                        float endThreshold) {
-            mController = controller;
-            mVibratorWrapper = vibratorWrapper;
-            mStartThreshold = startThreshold;
-            mEndThreshold = endThreshold;
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            if (mHasCommitted) {
-                return;
-            }
-            float currentProgress =
-                    AllAppsTransitionController.ALL_APPS_PROGRESS.get(mController);
-            if (currentProgress > mStartThreshold && currentProgress < mEndThreshold) {
-                mVibratorWrapper.vibrateForDragTexture();
-            } else if (!(currentProgress == 0 || currentProgress == 1)) {
-                // This check guards against committing at the location of the start of the gesture
-                mVibratorWrapper.vibrateForDragCommit();
-                mHasCommitted = true;
-            }
-        }
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 6dd811a..8e44d65 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -74,11 +74,17 @@
         public final CharSequence sectionName;
         // The item position
         public final int position;
+        // The view id associated with this section
+        public int id = -1;
 
         public FastScrollSectionInfo(CharSequence sectionName, int position) {
             this.sectionName = sectionName;
             this.position = position;
         }
+
+        public void setId(int id) {
+            this.id = id;
+        }
     }
 
 
diff --git a/src/com/android/launcher3/allapps/LetterListTextView.java b/src/com/android/launcher3/allapps/LetterListTextView.java
new file mode 100644
index 0000000..9326d79
--- /dev/null
+++ b/src/com/android/launcher3/allapps/LetterListTextView.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 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.allapps;
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Themes;
+
+/**
+ * A TextView that is used to display the letter list in the fast scroller.
+ */
+public class LetterListTextView extends TextView {
+    private static final float ABSOLUTE_TRANSLATION_X = 30f;
+    private static final float ABSOLUTE_SCALE = 1.4f;
+    private final Drawable mLetterBackground;
+    private final int mLetterListTextWidthAndHeight;
+    private final int mTextColor;
+    private final int mBackgroundColor;
+    private final int mSelectedColor;
+
+    public LetterListTextView(Context context) {
+        this(context, null, 0);
+    }
+
+    public LetterListTextView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public LetterListTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mLetterBackground = context.getDrawable(R.drawable.bg_letter_list_text);
+        mLetterListTextWidthAndHeight = context.getResources().getDimensionPixelSize(
+                R.dimen.fastscroll_list_letter_size);
+        mTextColor = Themes.getAttrColor(context, R.attr.materialColorOnSurface);
+        mBackgroundColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceContainer);
+        mSelectedColor = Themes.getAttrColor(context, R.attr.materialColorOnSecondary);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        setBackground(mLetterBackground);
+        setTextColor(mTextColor);
+        setClickable(false);
+        setWidth(mLetterListTextWidthAndHeight);
+        setTextSize(mLetterListTextWidthAndHeight);
+        setVisibility(VISIBLE);
+    }
+
+    /**
+     * Animates the letter list text view based on the current finger position.
+     *
+     * @param currentFingerY The Y position of where the finger is placed on the fastScroller in
+     *                       pixels.
+     */
+    public void animateBasedOnYPosition(int currentFingerY) {
+        if (getBackground() == null) {
+            return;
+        }
+        float cutOffMin = currentFingerY - (getHeight() * 2);
+        float cutOffMax = currentFingerY + (getHeight() * 2);
+        float cutOffDistance = cutOffMax - cutOffMin;
+        // Update the background blend color
+        boolean isWithinAnimationBounds = getY() < cutOffMax && getY() > cutOffMin;
+        if (isWithinAnimationBounds) {
+            getBackground().setColorFilter(new PorterDuffColorFilter(
+                    getBlendColorBasedOnYPosition(currentFingerY, cutOffDistance),
+                    PorterDuff.Mode.MULTIPLY));
+        } else {
+            getBackground().setColorFilter(new PorterDuffColorFilter(
+                    mBackgroundColor, PorterDuff.Mode.MULTIPLY));
+        }
+        translateBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+        scaleBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+    }
+
+    private int getBlendColorBasedOnYPosition(int y, float cutOffDistance) {
+        float raisedCosineBlend = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI);
+        float blendRatio = Utilities.boundToRange(raisedCosineBlend, 0f, 1f);
+        return ColorUtils.blendARGB(mBackgroundColor, mSelectedColor, blendRatio);
+    }
+
+    private void scaleBasedOnYPosition(int y, float cutOffDistance,
+            boolean isWithinAnimationBounds) {
+        float raisedCosineScale = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+                * ABSOLUTE_SCALE;
+        if (isWithinAnimationBounds) {
+            raisedCosineScale = Utilities.boundToRange(raisedCosineScale, 1f, ABSOLUTE_SCALE);
+            setScaleX(raisedCosineScale);
+            setScaleY(raisedCosineScale);
+        } else {
+            setScaleX(1);
+            setScaleY(1);
+        }
+    }
+
+    private void translateBasedOnYPosition(int y, float cutOffDistance,
+            boolean isWithinAnimationBounds) {
+        float raisedCosineTranslation =
+                (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+                        * ABSOLUTE_TRANSLATION_X;
+        if (isWithinAnimationBounds) {
+            raisedCosineTranslation = -1 * Utilities.boundToRange(raisedCosineTranslation,
+                    0, ABSOLUTE_TRANSLATION_X);
+            setTranslationX(raisedCosineTranslation);
+        } else {
+            setTranslationX(0);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index d0596fa..21900c1 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -93,18 +93,6 @@
             270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
             "Enable option to show keyboard when going to all-apps");
 
-    // TODO(Block 5): Clean up flags
-    public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
-            "ENABLE_TWOLINE_DEVICESEARCH", DISABLED,
-            "Enable two line label for icons with labels on device search.");
-
-    public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
-            "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader");
-
-    public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358,
-            "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED,
-            "Enables haptics opening/closing All apps");
-
     // TODO(Block 6): Clean up flags
     public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
             "ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", ENABLED,
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
new file mode 100644
index 0000000..3488c95
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.dagger;
+
+/**
+ * Launcher base component for Dagger injection.
+ *
+ * This class is not actually annotated as a Dagger component, since it is not used directly as one.
+ * Doing so generates unnecessary code bloat.
+ *
+ * See {@link LauncherAppComponent} for the one actually used by AOSP.
+ */
+public interface LauncherBaseAppComponent {
+    /** Builder for LauncherBaseAppComponent. */
+    interface Builder {
+        LauncherBaseAppComponent build();
+    }
+}
diff --git a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
index 650df5a..52b454f 100644
--- a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
+++ b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
@@ -17,6 +17,7 @@
 package com.android.launcher3.debug
 
 import android.content.Context
+import android.util.Log
 import com.android.launcher3.util.MainThreadInitializedObject
 import com.android.launcher3.util.SafeCloseable
 
@@ -26,6 +27,8 @@
     WORKSPACE_ON_DROP("WORKSPACE_ON_DROP"),
     RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"),
     WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"),
+    SPRING_LOADED_STATE_STARTED("SPRING_LOADED_STATE_STARTED"),
+    SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"),
 }
 
 /** Interface to create TestEventEmitters. */
@@ -50,5 +53,7 @@
 
     override fun close() {}
 
-    override fun sendEvent(event: TestEvent) {}
+    override fun sendEvent(event: TestEvent) {
+        Log.d("TestEventsEmitterProduction", "Event sent ${event.event}")
+    }
 }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3edf1f2..7bec768 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -773,6 +773,7 @@
         addAnimationStartListeners(anim);
         // Because t=0 has the folder match the folder icon, we can skip the
         // first frame and have the same movement one frame earlier.
+        Log.d("b/311077782", "Folder.animateOpen");
         anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration()));
         anim.start();
 
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a0b695a..de1bcc3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -83,7 +83,7 @@
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.util.ArrayList;
@@ -93,7 +93,7 @@
 /**
  * An icon that can appear on in the workspace representing an {@link Folder}.
  */
-public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
+public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
         DraggableView, Reorderable {
 
     private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index dc8694d..374c07b 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -32,6 +32,7 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.Message;
 import android.os.Messenger;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
@@ -80,8 +81,10 @@
     private static final String KEY_SURFACE_PACKAGE = "surface_package";
     private static final String KEY_CALLBACK = "callback";
     public static final String KEY_HIDE_BOTTOM_ROW = "hide_bottom_row";
+    public static final String KEY_GRID_NAME = "grid_name";
 
     private static final int MESSAGE_ID_UPDATE_PREVIEW = 1337;
+    private static final int MESSAGE_ID_UPDATE_GRID = 7414;
 
     /**
      * Here we use the IBinder and the screen ID as the key of the active previews.
@@ -245,11 +248,22 @@
             if (destroyed) {
                 return true;
             }
-            if (message.what == MESSAGE_ID_UPDATE_PREVIEW) {
-                renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
-            } else {
-                destroyObserver(this);
+
+            switch (message.what) {
+                case MESSAGE_ID_UPDATE_PREVIEW:
+                    renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
+                    break;
+                case MESSAGE_ID_UPDATE_GRID:
+                    String gridName = message.getData().getString(KEY_GRID_NAME);
+                    if (!TextUtils.isEmpty(gridName)) {
+                        renderer.updateGrid(gridName);
+                    }
+                    break;
+                default:
+                    destroyObserver(this);
+                    break;
             }
+
             return true;
         }
 
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index addd072..56c4ca4 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -38,6 +38,7 @@
 import android.view.SurfaceControlViewHost.SurfacePackage;
 import android.view.View;
 import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -61,6 +62,7 @@
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.widget.LocalColorExtractor;
+import com.android.systemui.shared.Flags;
 
 import java.util.ArrayList;
 import java.util.Map;
@@ -96,6 +98,7 @@
     private boolean mDestroyed = false;
     private LauncherPreviewRenderer mRenderer;
     private boolean mHideQsb;
+    @Nullable private FrameLayout mViewRoot = null;
 
     public PreviewSurfaceRenderer(Context context, Bundle bundle) throws Exception {
         mContext = context;
@@ -194,6 +197,19 @@
     }
 
     /**
+     * Update the grid of the launcher preview
+     *
+     * @param gridName Name of the grid, e.g. normal, practical
+     */
+    public void updateGrid(@NonNull String gridName) {
+        if (gridName.equals(mGridName)) {
+            return;
+        }
+        mGridName = gridName;
+        loadAsync();
+    }
+
+    /**
      * Hides the components in the bottom row.
      *
      * @param hide True to hide and false to show.
@@ -302,11 +318,41 @@
         view.setPivotY(0);
         view.setTranslationX((mWidth - scale * view.getWidth()) / 2);
         view.setTranslationY((mHeight - scale * view.getHeight()) / 2);
-        view.setAlpha(0);
-        view.animate().alpha(1)
-                .setInterpolator(new AccelerateDecelerateInterpolator())
-                .setDuration(FADE_IN_ANIMATION_DURATION)
-                .start();
-        mSurfaceControlViewHost.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());
+        if (!Flags.newCustomizationPickerUi()) {
+            view.setAlpha(0);
+            view.animate().alpha(1)
+                    .setInterpolator(new AccelerateDecelerateInterpolator())
+                    .setDuration(FADE_IN_ANIMATION_DURATION)
+                    .start();
+            mSurfaceControlViewHost.setView(
+                    view,
+                    view.getMeasuredWidth(),
+                    view.getMeasuredHeight()
+            );
+            return;
+        }
+
+        if (mViewRoot == null) {
+            mViewRoot = new FrameLayout(inflationContext);
+            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.WRAP_CONTENT, // Width
+                    FrameLayout.LayoutParams.WRAP_CONTENT  // Height
+            );
+            mViewRoot.setLayoutParams(layoutParams);
+            mViewRoot.addView(view);
+            mViewRoot.setAlpha(0);
+            mViewRoot.animate().alpha(1)
+                    .setInterpolator(new AccelerateDecelerateInterpolator())
+                    .setDuration(FADE_IN_ANIMATION_DURATION)
+                    .start();
+            mSurfaceControlViewHost.setView(
+                    mViewRoot,
+                    view.getMeasuredWidth(),
+                    view.getMeasuredHeight()
+            );
+        } else  {
+            mViewRoot.removeAllViews();
+            mViewRoot.addView(view);
+        }
     }
 }
diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
index 406f697..de2269c 100644
--- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
+++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
@@ -18,10 +18,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.LauncherActivityInfo;
+import android.os.Build;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.BaseIconFactory.IconOptions;
@@ -64,9 +66,16 @@
     @Override
     public BitmapInfo loadIcon(@NonNull Context context, @NonNull LauncherActivityInfo object) {
         try (LauncherIcons li = LauncherIcons.obtain(context)) {
-            return li.createBadgedIconBitmap(LauncherAppState.getInstance(context)
-                            .getIconProvider().getIcon(object, li.mFillResIconDpi),
-                    new IconOptions().setUser(object.getUser()));
+            IconOptions iconOptions = new IconOptions().setUser(object.getUser());
+            iconOptions.mIsArchived = Flags.useNewIconForArchivedApps()
+                && Build.VERSION.SDK_INT >= 35
+                && object.getActivityInfo().isArchived;
+            return li.createBadgedIconBitmap(
+                    LauncherAppState.getInstance(context)
+                        .getIconProvider()
+                        .getIcon(object, li.mFillResIconDpi),
+                    iconOptions
+            );
         }
     }
 }
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 551c2d8..59d1d00 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -192,22 +192,18 @@
     }
 
     private void queuePendingShortcutInfo(PendingInstallShortcutInfo info) {
-        final Exception stackTrace = new Exception();
 
         // Queue the item up for adding if launcher has not loaded properly yet
         MODEL_EXECUTOR.post(() -> {
             Pair<ItemInfo, Object> itemInfo = info.getItemInfo(mContext);
             if (itemInfo == null) {
                 FileLog.d(LOG,
-                        "Adding PendingInstallShortcutInfo with no attached info to queue.",
-                        stackTrace);
+                        "Adding PendingInstallShortcutInfo with no attached info to queue.");
             } else {
                 FileLog.d(LOG,
-                        "Adding PendingInstallShortcutInfo to queue. Attached info: "
-                                + itemInfo.first,
-                        stackTrace);
+                        "Adding PendingInstallShortcutInfo to queue."
+                                + " Attached info: " + itemInfo.first);
             }
-
             addToQueue(info);
         });
         flushInstallQueue();
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 269cb9f..605accf 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -209,7 +209,10 @@
                 mApp.getContext().getContentResolver(),
                 "launcher_broadcast_installed_apps",
                 /* def= */ 0);
-        if (launcherBroadcastInstalledApps == 1 && mIsRestoreFromBackup) {
+        boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
+                && (launcherBroadcastInstalledApps == 1
+                        || Flags.enableFirstScreenBroadcastArchivingExtras());
+        if (shouldAttachArchivingExtras) {
             List<FirstScreenBroadcastModel> broadcastModels =
                     FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
                             mPmHelper,
diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
index b12b2bc..2ee5b80 100644
--- a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
+++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
@@ -38,6 +38,7 @@
     LauncherApps.Callback() {
 
     override fun onPackageAdded(packageName: String, user: UserHandle) {
+        FileLog.d(TAG, "onPackageAdded triggered for packageName=$packageName, user=$user")
         taskExecutor.accept(PackageUpdatedTask(OP_ADD, user, packageName))
     }
 
@@ -54,7 +55,7 @@
     }
 
     override fun onPackageRemoved(packageName: String, user: UserHandle) {
-        FileLog.d(TAG, "package removed received $packageName")
+        FileLog.d(TAG, "onPackageRemoved triggered for packageName=$packageName, user=$user")
         taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, packageName))
     }
 
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index b82d0a0..62198cb 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -51,6 +51,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logger.LauncherAtom.AllAppsContainer;
+import com.android.launcher3.logger.LauncherAtom.Attribute;
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
 import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
 import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
@@ -67,6 +68,9 @@
 import com.android.launcher3.util.UserIconInfo;
 import com.android.systemui.shared.system.SysUiStatsLog;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 
 /**
@@ -187,6 +191,12 @@
     @NonNull
     public UserHandle user;
 
+    @NonNull
+    private ExtendedContainers mExtendedContainers = ExtendedContainers.getDefaultInstance();
+
+    @NonNull
+    private List<Attribute> mAttributeList = Collections.EMPTY_LIST;
+
     public ItemInfo() {
         user = Process.myUserHandle();
     }
@@ -433,6 +443,7 @@
         UserCache.INSTANCE.executeIfCreated(cache ->
                 itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
         itemBuilder.setRank(rank);
+        itemBuilder.addAllItemAttributes(mAttributeList);
         return itemBuilder;
     }
 
@@ -491,7 +502,7 @@
             default:
                 if (container <= EXTENDED_CONTAINERS) {
                     return ContainerInfo.newBuilder()
-                            .setExtendedContainers(getExtendedContainer())
+                            .setExtendedContainers(mExtendedContainers)
                             .build();
                 }
         }
@@ -499,12 +510,21 @@
     }
 
     /**
-     * Returns non-AOSP container wrapped by {@link ExtendedContainers} object. Should be overridden
-     * by build variants.
+     * Sets extra container info wrapped by {@link ExtendedContainers} object.
      */
-    @NonNull
-    protected ExtendedContainers getExtendedContainer() {
-        return ExtendedContainers.getDefaultInstance();
+    public void setExtendedContainers(@NonNull ExtendedContainers extendedContainers) {
+        mExtendedContainers = extendedContainers;
+    }
+
+    /**
+     * Adds extra attributes to be added during logs
+     */
+    public void addLogAttributes(List<LauncherAtom.Attribute> attributeList) {
+        if (mAttributeList.isEmpty()) {
+            mAttributeList = new ArrayList<>(attributeList);
+        } else {
+            mAttributeList.addAll(attributeList);
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
deleted file mode 100644
index bde4e52..0000000
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package com.android.launcher3.pageindicators;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
-
-/**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages
- *
- * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
- */
-public class WorkspacePageIndicator extends View implements Insettable, PageIndicator {
-
-    private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
-    private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
-    public static final int WHITE_ALPHA = (int) (0.70f * 255);
-    public static final int BLACK_ALPHA = (int) (0.65f * 255);
-
-    private static final int LINE_ALPHA_ANIMATOR_INDEX = 0;
-    private static final int NUM_PAGES_ANIMATOR_INDEX = 1;
-    private static final int TOTAL_SCROLL_ANIMATOR_INDEX = 2;
-    private static final int ANIMATOR_COUNT = 3;
-
-    private ValueAnimator[] mAnimators = new ValueAnimator[ANIMATOR_COUNT];
-
-    private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
-    private final Launcher mLauncher;
-
-    private boolean mShouldAutoHide = true;
-
-    // The alpha of the line when it is showing.
-    private int mActiveAlpha = 0;
-    // The alpha that the line is being animated to or already at (either 0 or mActiveAlpha).
-    private int mToAlpha;
-    // A float value representing the number of pages, to allow for an animation when it changes.
-    private float mNumPagesFloat;
-    private int mCurrentScroll;
-    private int mTotalScroll;
-    private Paint mLinePaint;
-    private final int mLineHeight;
-
-    private static final Property<WorkspacePageIndicator, Integer> PAINT_ALPHA
-            = new Property<WorkspacePageIndicator, Integer>(Integer.class, "paint_alpha") {
-        @Override
-        public Integer get(WorkspacePageIndicator obj) {
-            return obj.mLinePaint.getAlpha();
-        }
-
-        @Override
-        public void set(WorkspacePageIndicator obj, Integer alpha) {
-            obj.mLinePaint.setAlpha(alpha);
-            obj.invalidate();
-        }
-    };
-
-    private static final Property<WorkspacePageIndicator, Float> NUM_PAGES
-            = new Property<WorkspacePageIndicator, Float>(Float.class, "num_pages") {
-        @Override
-        public Float get(WorkspacePageIndicator obj) {
-            return obj.mNumPagesFloat;
-        }
-
-        @Override
-        public void set(WorkspacePageIndicator obj, Float numPages) {
-            obj.mNumPagesFloat = numPages;
-            obj.invalidate();
-        }
-    };
-
-    private static final Property<WorkspacePageIndicator, Integer> TOTAL_SCROLL
-            = new Property<WorkspacePageIndicator, Integer>(Integer.class, "total_scroll") {
-        @Override
-        public Integer get(WorkspacePageIndicator obj) {
-            return obj.mTotalScroll;
-        }
-
-        @Override
-        public void set(WorkspacePageIndicator obj, Integer totalScroll) {
-            obj.mTotalScroll = totalScroll;
-            obj.invalidate();
-        }
-    };
-
-    private Runnable mHideLineRunnable = () -> animateLineToAlpha(0);
-
-    public WorkspacePageIndicator(Context context) {
-        this(context, null);
-    }
-
-    public WorkspacePageIndicator(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public WorkspacePageIndicator(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        Resources res = context.getResources();
-        mLinePaint = new Paint();
-        mLinePaint.setAlpha(0);
-
-        mLauncher = Launcher.getLauncher(context);
-        mLineHeight = res.getDimensionPixelSize(R.dimen.workspace_page_indicator_line_height);
-
-        boolean darkText = Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText);
-        mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
-        mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mTotalScroll == 0 || mNumPagesFloat == 0) {
-            return;
-        }
-
-        // Compute and draw line rect.
-        float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
-        int availableWidth = getWidth();
-        int lineWidth = (int) (availableWidth / mNumPagesFloat);
-        int lineLeft = (int) (progress * (availableWidth - lineWidth));
-        int lineRight = lineLeft + lineWidth;
-
-        canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight,
-                getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
-    }
-
-    @Override
-    public void setScroll(int currentScroll, int totalScroll) {
-        if (getAlpha() == 0) {
-            return;
-        }
-        animateLineToAlpha(mActiveAlpha);
-
-        mCurrentScroll = currentScroll;
-        if (mTotalScroll == 0) {
-            mTotalScroll = totalScroll;
-        } else if (mTotalScroll != totalScroll) {
-            animateToTotalScroll(totalScroll);
-        } else {
-            invalidate();
-        }
-
-        if (mShouldAutoHide) {
-            hideAfterDelay();
-        }
-    }
-
-    private void hideAfterDelay() {
-        mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
-        mDelayedLineFadeHandler.postDelayed(mHideLineRunnable, LINE_FADE_DELAY);
-    }
-
-    @Override
-    public void setActiveMarker(int activePage) { }
-
-    @Override
-    public void setMarkersCount(int numMarkers) {
-        if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
-            setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers),
-                    NUM_PAGES_ANIMATOR_INDEX);
-        } else {
-            if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) {
-                mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel();
-                mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null;
-            }
-        }
-    }
-
-    @Override
-    public void setShouldAutoHide(boolean shouldAutoHide) {
-        mShouldAutoHide = shouldAutoHide;
-        if (shouldAutoHide && mLinePaint.getAlpha() > 0) {
-            hideAfterDelay();
-        } else if (!shouldAutoHide) {
-            mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
-        }
-    }
-
-    private void animateLineToAlpha(int alpha) {
-        if (alpha == mToAlpha) {
-            // Ignore the new animation if it is going to the same alpha as the current animation.
-            return;
-        }
-        mToAlpha = alpha;
-        setupAndRunAnimation(ObjectAnimator.ofInt(this, PAINT_ALPHA, alpha),
-                LINE_ALPHA_ANIMATOR_INDEX);
-    }
-
-    private void animateToTotalScroll(int totalScroll) {
-        setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
-                TOTAL_SCROLL_ANIMATOR_INDEX);
-    }
-
-    /**
-     * Starts the given animator and stores it in the provided index in {@link #mAnimators} until
-     * the animation ends.
-     *
-     * If an animator is already at the index (i.e. it is already playing), it is canceled and
-     * replaced with the new animator.
-     */
-    private void setupAndRunAnimation(ValueAnimator animator, final int animatorIndex) {
-        if (mAnimators[animatorIndex] != null) {
-            mAnimators[animatorIndex].cancel();
-        }
-        mAnimators[animatorIndex] = animator;
-        mAnimators[animatorIndex].addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimators[animatorIndex] = null;
-            }
-        });
-        mAnimators[animatorIndex].setDuration(LINE_ANIMATE_DURATION);
-        mAnimators[animatorIndex].start();
-    }
-
-    /**
-     * Pauses all currently running animations.
-     */
-    @Override
-    public void pauseAnimations() {
-        for (int i = 0; i < ANIMATOR_COUNT; i++) {
-            if (mAnimators[i] != null) {
-                mAnimators[i].pause();
-            }
-        }
-    }
-
-    /**
-     * Force-ends all currently running or paused animations.
-     */
-    @Override
-    public void skipAnimationsToEnd() {
-        for (int i = 0; i < ANIMATOR_COUNT; i++) {
-            if (mAnimators[i] != null) {
-                mAnimators[i].end();
-            }
-        }
-    }
-
-    /**
-     * We need to override setInsets to prevent InsettableFrameLayout from applying different
-     * margins on the page indicator.
-     */
-    @Override
-    public void setInsets(Rect insets) {
-    }
-}
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index c117be4..856c294 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.os.Build;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
@@ -32,6 +33,7 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.Flags;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.util.PackageUserKey;
 
 import java.lang.ref.WeakReference;
@@ -41,6 +43,8 @@
 @WorkerThread
 public class InstallSessionTracker extends PackageInstaller.SessionCallback {
 
+    public static final String TAG = "InstallSessionTracker";
+
     // Lazily initialized
     private SparseArray<PackageUserKey> mActiveSessions = null;
 
@@ -75,6 +79,11 @@
         }
         SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
         if (sessionInfo != null) {
+            FileLog.d(TAG, "onCreated: Install session created for"
+                    + " appPackageName=" + sessionInfo.getAppPackageName()
+                    + ", sessionId=" + sessionInfo.getSessionId()
+                    + ", appIcon=" + sessionInfo.getAppIcon()
+                    + ", appLabel=" + sessionInfo.getAppLabel());
             callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
         }
 
@@ -102,6 +111,10 @@
         activeSessions.remove(sessionId);
 
         if (key != null && key.mPackageName != null) {
+            FileLog.d(TAG, "onFinished: active install session finished for"
+                    + " appPackageName=" + key.mPackageName
+                    + ", sessionId=" + sessionId
+                    + ", success=" + success);
             String packageName = key.mPackageName;
             PackageInstallInfo info = PackageInstallInfo.fromState(
                     success ? STATUS_INSTALLED : STATUS_FAILED,
@@ -141,6 +154,11 @@
         }
         SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
         if (sessionInfo != null) {
+            Log.d(TAG, "onBadgingChanged: badging info changed for"
+                    + " appPackageName=" + sessionInfo.getAppPackageName()
+                    + ", sessionId=" + sessionInfo.getSessionId()
+                    + ", appIcon=" + sessionInfo.getAppIcon()
+                    + ", appLabel=" + sessionInfo.getAppLabel());
             helper.tryQueuePromiseAppIcon(sessionInfo);
         }
     }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 4d4a8f7..c2debfa 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher3.popup;
 
-import static androidx.core.content.ContextCompat.getColorStateList;
-
 import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
 import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.app.animation.Interpolators.LINEAR;
@@ -56,8 +54,6 @@
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
-import java.util.Arrays;
-
 /**
  * A container for shortcuts to deep links and notifications associated with an app.
  *
@@ -130,7 +126,7 @@
     // Tag for Views that have children that will need to be iterated to add styling.
     private final String mIterateChildrenTag;
 
-    protected final int[] mColorIds;
+    protected final int[] mColors;
 
     public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -142,8 +138,7 @@
 
         // Initialize arrow view
         final Resources resources = getResources();
-        mArrowColor = getColorStateList(getContext(), R.color.popup_color_background)
-                .getDefaultColor();
+        mArrowColor = Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceContainer);
         mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
         mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
         mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
@@ -158,21 +153,25 @@
         mRoundedTop = new GradientDrawable();
         int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
         mRoundedTop.setColor(popupPrimaryColor);
-        mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
+        mRoundedTop.setCornerRadii(new float[]{mOutlineRadius, mOutlineRadius, mOutlineRadius,
                 mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
 
         mRoundedBottom = new GradientDrawable();
         mRoundedBottom.setColor(popupPrimaryColor);
-        mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
+        mRoundedBottom.setCornerRadii(new float[]{smallerRadius, smallerRadius, smallerRadius,
                 smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
 
         mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
 
         if (mActivityContext.canUseMultipleShadesForPopup()) {
-            mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
-                    R.color.popup_shade_third};
+            mColors = new int[]{
+                    getContext().getColor(R.color.popup_shade_first),
+                    getContext().getColor(R.color.popup_shade_second),
+                    getContext().getColor(R.color.popup_shade_third)
+            };
         } else {
-            mColorIds = new int[]{R.color.popup_color_background};
+            mColors = new int[]{Themes.getAttrColor(getContext(),
+                    R.attr.materialColorSurfaceContainer)};
         }
     }
 
@@ -219,15 +218,14 @@
     }
 
     /**
-     * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}.
+     * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}.
      *                        Otherwise, we will use this color for all child views.
      */
     protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
         int[] colors = null;
         if (backgroundColor == Color.TRANSPARENT) {
             // Lazily get the colors so they match the current wallpaper colors.
-            colors = Arrays.stream(mColorIds).map(
-                    r -> getColorStateList(getContext(), r).getDefaultColor()).toArray();
+            colors = mColors;
         }
 
         int count = viewGroup.getChildCount();
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index ac07c0f..303290d 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -253,7 +253,7 @@
             if (mConfig.currentAnimation == null) {
                 // Run any queued runnable
                 if (listener != null) {
-                    listener.onAnimationEnd(null);
+                    listener.onAnimationEnd(new AnimatorSet());
                 }
                 return;
             } else if ((!mConfig.isUserControlled() && animated && mConfig.targetState == state)
@@ -282,7 +282,7 @@
 
             // Run any queued runnable
             if (listener != null) {
-                listener.onAnimationEnd(null);
+                listener.onAnimationEnd(new AnimatorSet());
             }
             return;
         }
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 6bae1ba..a4b8eb0 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -25,12 +25,10 @@
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.net.Uri;
-import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.Utilities;
@@ -54,20 +52,6 @@
     static final Uri HAPTIC_FEEDBACK_URI = Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
 
     @VisibleForTesting static final float LOW_TICK_SCALE = 0.9f;
-    @VisibleForTesting static final float DRAG_TEXTURE_SCALE = 0.03f;
-    @VisibleForTesting static final float DRAG_COMMIT_SCALE = 0.5f;
-    @VisibleForTesting static final float DRAG_BUMP_SCALE = 0.4f;
-    @VisibleForTesting static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
-
-    @Nullable
-    private final VibrationEffect mDragEffect;
-    @Nullable
-    private final VibrationEffect mCommitEffect;
-    @Nullable
-    private final VibrationEffect mBumpEffect;
-
-    private long mLastDragTime;
-    private final int mThresholdUntilNextDragCallMillis;
 
     /**
      * Haptic when entering overview.
@@ -100,28 +84,6 @@
         } else {
             mIsHapticFeedbackEnabled = false;
         }
-
-        if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(
-                PRIMITIVE_LOW_TICK)) {
-
-            // Drag texture, Commit, and Bump should only be used for premium phones.
-            // Before using these haptics make sure check if the device can use it
-            mDragEffect = getDragEffect();
-            mCommitEffect = VibrationEffect.startComposition().addPrimitive(
-                    VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose();
-            mBumpEffect = VibrationEffect.startComposition().addPrimitive(
-                    PRIMITIVE_LOW_TICK, DRAG_BUMP_SCALE).compose();
-            int primitiveDuration = mVibrator.getPrimitiveDurations(
-                    PRIMITIVE_LOW_TICK)[0];
-
-            mThresholdUntilNextDragCallMillis =
-                    DRAG_TEXTURE_EFFECT_SIZE * primitiveDuration + 100;
-        } else {
-            mDragEffect = null;
-            mCommitEffect = null;
-            mBumpEffect = null;
-            mThresholdUntilNextDragCallMillis = 0;
-        }
     }
 
     @Override
@@ -132,52 +94,11 @@
     }
 
     /**
-     * This is called when the user swipes to/from all apps. This is meant to be used in between
-     * long animation progresses so that it gives a dragging texture effect. For a better
-     * experience, this should be used in combination with vibrateForDragCommit().
-     */
-    public void vibrateForDragTexture() {
-        if (mDragEffect == null) {
-            return;
-        }
-        long currentTime = SystemClock.elapsedRealtime();
-        long elapsedTimeSinceDrag = currentTime - mLastDragTime;
-        if (elapsedTimeSinceDrag >= mThresholdUntilNextDragCallMillis) {
-            vibrate(mDragEffect);
-            mLastDragTime = currentTime;
-        }
-    }
-
-    /**
-     * This is used when user reaches the commit threshold when swiping to/from from all apps.
-     */
-    public void vibrateForDragCommit() {
-        if (mCommitEffect != null) {
-            vibrate(mCommitEffect);
-        }
-        // resetting dragTexture timestamp to be able to play dragTexture again
-        mLastDragTime = 0;
-    }
-
-    /**
-     * The bump haptic is used to be called at the end of a swipe and only if it the gesture is a
-     * FLING going to/from all apps. Client can just call this method elsewhere just for the
-     * effect.
-     */
-    public void vibrateForDragBump() {
-        if (mBumpEffect != null) {
-            vibrate(mBumpEffect);
-        }
-    }
-
-    /**
      * This should be used to cancel a haptic in case where the haptic shouldn't be vibrating. For
      * example, when no animation is happening but a vibrator happens to be vibrating still.
      */
     public void cancelVibrate() {
         UI_HELPER_EXECUTOR.execute(mVibrator::cancel);
-        // reset dragTexture timestamp to be able to play dragTexture again whenever cancelled
-        mLastDragTime = 0;
     }
 
     /** Vibrates with the given effect if haptic feedback is available and enabled. */
@@ -217,13 +138,4 @@
             vibrate(primitiveLowTickEffect);
         }
     }
-
-    static VibrationEffect getDragEffect() {
-        VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
-        for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
-            dragEffect.addPrimitive(
-                    PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
-        }
-        return dragEffect.compose();
-    }
 }
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 84f8049..d2ae93b 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -20,7 +20,7 @@
 /**
  * Views that contain {@link BubbleTextView} should implement this interface.
  */
-public interface BubbleTextHolder extends IconLabelDotView {
+public interface BubbleTextHolder extends FloatingIconViewCompanion {
     BubbleTextView getBubbleText();
 
     @Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 1e577be..4ee6aff 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -22,7 +22,7 @@
 import static com.android.launcher3.Utilities.getFullDrawable;
 import static com.android.launcher3.Utilities.mapToRange;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
 
 import android.animation.Animator;
 import android.content.Context;
@@ -175,8 +175,9 @@
                 mLauncher.getDeviceProfile(), taskViewDrawAlpha);
 
         if (mFadeOutView != null) {
-            // The alpha goes from 1 to 0 when progress is 0 and 0.33 respectively.
-            mFadeOutView.setAlpha(1 - Math.min(1f, mapToRange(progress, 0, 0.33f, 0, 1, LINEAR)));
+            // The alpha goes from 1 to 0 when progress is 0 and 0.15 respectively.
+            // This value minimizes view display time while still allowing the view to fade out.
+            mFadeOutView.setAlpha(1 - Math.min(1f, mapToRange(progress, 0, 0.15f, 0, 1, LINEAR)));
         }
     }
 
@@ -515,6 +516,10 @@
             // When closing an app, we want the item on the workspace to be invisible immediately
             updateViewsVisibility(false  /* isVisible */);
         }
+        if (mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+            fivc.setForceHideDot(true);
+            fivc.setForceHideRing(true);
+        }
     }
 
     @Override
@@ -652,6 +657,10 @@
             if (view.mFadeOutView != null) {
                 view.mFadeOutView.setAlpha(1f);
             }
+            if (view.mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+                fivc.setForceHideDot(false);
+                fivc.setForceHideRing(false);
+            }
 
             if (hideOriginal) {
                 view.updateViewsVisibility(true /* isVisible */);
@@ -673,10 +682,10 @@
 
     private void updateViewsVisibility(boolean isVisible) {
         if (mOriginalIcon != null) {
-            setIconAndDotVisible(mOriginalIcon, isVisible);
+            setPropertiesVisible(mOriginalIcon, isVisible);
         }
         if (mMatchVisibilityView != null) {
-            setIconAndDotVisible(mMatchVisibilityView, isVisible);
+            setPropertiesVisible(mMatchVisibilityView, isVisible);
         }
     }
 
diff --git a/src/com/android/launcher3/views/FloatingIconViewCompanion.java b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
new file mode 100644
index 0000000..fc23903
--- /dev/null
+++ b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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.views;
+
+import android.view.View;
+
+/**
+ * A view that can be drawn (in some capacity) via) {@link FloatingIconView}.
+ * This interface allows us to hide certain properties of the view that the FloatingIconView
+ * cannot draw, which allows us to make a seamless handoff between the FloatingIconView and
+ * the companion view.
+ */
+public interface FloatingIconViewCompanion {
+    void setIconVisible(boolean visible);
+    void setForceHideDot(boolean hide);
+    default void setForceHideRing(boolean hide) {}
+
+    /**
+     * Sets the visibility of icon and dot of the view
+     */
+    static void setPropertiesVisible(View view, boolean visible) {
+        if (view instanceof FloatingIconViewCompanion) {
+            ((FloatingIconViewCompanion) view).setIconVisible(visible);
+            ((FloatingIconViewCompanion) view).setForceHideDot(!visible);
+            ((FloatingIconViewCompanion) view).setForceHideRing(!visible);
+        } else {
+            view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index cab7982..7fa7517 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -17,7 +17,7 @@
 
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -237,7 +237,7 @@
 
     private void setCurrentIconVisible(boolean isVisible) {
         if (mIcon != null) {
-            setIconAndDotVisible(mIcon, isVisible);
+            setPropertiesVisible(mIcon, isVisible);
         }
     }
 }
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
deleted file mode 100644
index e9113cf..0000000
--- a/src/com/android/launcher3/views/IconLabelDotView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 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.views;
-
-import android.view.View;
-
-/**
- * A view that has an icon, label, and notification dot.
- */
-public interface IconLabelDotView {
-    void setIconVisible(boolean visible);
-    void setForceHideDot(boolean hide);
-
-    /**
-     * Sets the visibility of icon and dot of the view
-     */
-    static void setIconAndDotVisible(View view, boolean visible) {
-        if (view instanceof IconLabelDotView) {
-            ((IconLabelDotView) view).setIconVisible(visible);
-            ((IconLabelDotView) view).setForceHideDot(!visible);
-        } else {
-            view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 62eed5c..82cc40d 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.views;
 
-import static androidx.core.content.ContextCompat.getColorStateList;
-
 import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
@@ -147,8 +145,7 @@
 
     @Override
     public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
-        assignMarginsAndBackgrounds(viewGroup,
-                getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+        assignMarginsAndBackgrounds(viewGroup, mColors[0]);
         // last shortcut doesn't need bottom margin
         final int count = viewGroup.getChildCount() - 1;
         for (int i = 0; i < count; i++) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index fa17b7b..63648dd 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -20,6 +20,9 @@
 
 import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
 
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
+
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
@@ -40,11 +43,15 @@
 import android.view.WindowInsets;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.LetterListTextView;
 import com.android.launcher3.graphics.FastScrollThumbDrawable;
 import com.android.launcher3.util.Themes;
 
@@ -55,6 +62,19 @@
  * The track and scrollbar that shows when you scroll the list.
  */
 public class RecyclerViewFastScroller extends View {
+
+    /** FastScrollerLocation describes what RecyclerView the fast scroller is dedicated to. */
+    public enum FastScrollerLocation {
+        UNKNOWN_SCROLLER(0),
+        ALL_APPS_SCROLLER(1),
+        WIDGET_SCROLLER(2);
+
+        public final int location;
+
+        FastScrollerLocation(int location) {
+            this.location = location;
+        }
+    }
     private static final String TAG = "RecyclerViewFastScroller";
     private static final boolean DEBUG = false;
     private static final int FASTSCROLL_THRESHOLD_MILLIS = 40;
@@ -106,6 +126,8 @@
     private final Point mThumbDrawOffset = new Point();
 
     private final Paint mTrackPaint;
+    private final int mThumbColor;
+    private final int mThumbLetterScrollerColor;
 
     private float mLastTouchY;
     private boolean mIsDragging;
@@ -139,6 +161,7 @@
     private int mDownX;
     private int mDownY;
     private int mLastY;
+    private FastScrollerLocation mFastScrollerLocation;
 
     public RecyclerViewFastScroller(Context context) {
         this(context, null);
@@ -151,13 +174,16 @@
     public RecyclerViewFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        mFastScrollerLocation = FastScrollerLocation.UNKNOWN_SCROLLER;
         mTrackPaint = new Paint();
         mTrackPaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
         mTrackPaint.setAlpha(MAX_TRACK_ALPHA);
 
+        mThumbColor = Themes.getColorAccent(context);
+        mThumbLetterScrollerColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceBright);
         mThumbPaint = new Paint();
         mThumbPaint.setAntiAlias(true);
-        mThumbPaint.setColor(Themes.getColorAccent(context));
+        mThumbPaint.setColor(mThumbColor);
         mThumbPaint.setStyle(Paint.Style.FILL);
 
         Resources res = getResources();
@@ -334,6 +360,18 @@
         animatePopupVisibility(!TextUtils.isEmpty(sectionName));
         mLastTouchY = boundedY;
         setThumbOffsetY((int) mLastTouchY);
+        updateFastScrollerLetterList(y);
+    }
+
+    private void updateFastScrollerLetterList(int y) {
+        if (!shouldUseLetterFastScroller()) {
+            return;
+        }
+        ConstraintLayout mLetterList = mRv.getLetterList();
+        for (int i = 0; i < mLetterList.getChildCount(); i++) {
+            LetterListTextView currentLetter = (LetterListTextView) mLetterList.getChildAt(i);
+            currentLetter.animateBasedOnYPosition(y + mTouchOffsetY);
+        }
     }
 
     /** End any active fast scrolling touch handling, if applicable. */
@@ -359,15 +397,35 @@
         mThumbDrawOffset.set(getWidth() / 2, mRv.getScrollBarTop());
         // Draw the track
         float halfW = mWidth / 2;
-        canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
-                mWidth, mWidth, mTrackPaint);
-
-        canvas.translate(0, mThumbOffsetY);
+        boolean useLetterFastScroller = shouldUseLetterFastScroller();
+        if (useLetterFastScroller) {
+            float translateX;
+            if (mIsDragging) {
+                // halfW * 3 is half circle.
+                translateX = halfW * 3;
+            } else {
+                translateX = halfW * 5;
+            }
+            canvas.translate(translateX, mThumbOffsetY);
+        } else {
+            canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
+                    mWidth, mWidth, mTrackPaint);
+            canvas.translate(0, mThumbOffsetY);
+        }
         mThumbDrawOffset.y += mThumbOffsetY;
+
+        /* Draw half circle */
         halfW += mThumbPadding;
         float r = getScrollThumbRadius();
-        mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
-        canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+        if (useLetterFastScroller) {
+            mThumbPaint.setColor(mThumbLetterScrollerColor);
+            mThumbBounds.set(0, 0, 0, mThumbHeight);
+            canvas.drawCircle(-halfW, halfW, r * 2, mThumbPaint);
+        } else {
+            mThumbPaint.setColor(mThumbColor);
+            mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
+            canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+        }
         mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
         // swiping very close to the thumb area (not just within it's bound)
         // will also prevent back gesture
@@ -380,6 +438,11 @@
         canvas.restoreToCount(saveCount);
     }
 
+    boolean shouldUseLetterFastScroller() {
+        return Flags.letterFastScroller()
+                && getScrollerLocation() == FastScrollerLocation.ALL_APPS_SCROLLER;
+    }
+
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mSystemGestureInsets = insets.getSystemGestureInsets();
@@ -421,19 +484,25 @@
         return isNearThumb(x, y);
     }
 
-    /**
-     * Returns whether the specified x position is near the scroll bar.
-     */
-    public boolean isNearScrollBar(int x) {
-        return x >= (getWidth() - mMaxWidth) / 2 - mScrollbarLeftOffsetTouchDelegate
-                && x <= (getWidth() + mMaxWidth) / 2;
+    public FastScrollerLocation getScrollerLocation() {
+        return mFastScrollerLocation;
+    }
+
+    public void setFastScrollerLocation(@NonNull FastScrollerLocation location) {
+        mFastScrollerLocation = location;
     }
 
     private void animatePopupVisibility(boolean visible) {
         if (mPopupVisible != visible) {
             mPopupVisible = visible;
-            mPopupView.animate().cancel();
-            mPopupView.animate().alpha(visible ? 1f : 0f).setDuration(visible ? 200 : 150).start();
+            if (shouldUseLetterFastScroller()) {
+                mRv.getLetterList().animate().alpha(visible ? 1f : 0f)
+                        .setDuration(visible ? 200 : 150).start();
+            } else {
+                mPopupView.animate().cancel();
+                mPopupView.animate().alpha(visible ? 1f : 0f)
+                        .setDuration(visible ? 200 : 150).start();
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 2af8e6f..c8ad564 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
 
 import android.animation.Animator;
 import android.content.Context;
@@ -119,7 +120,7 @@
                     WidgetsRecyclerView searchRecyclerView =
                             mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView;
                     if (mIsInSearchMode && searchRecyclerView != null) {
-                        searchRecyclerView.bindFastScrollbar(mFastScroller);
+                        searchRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
                     }
                 }
 
@@ -276,7 +277,7 @@
     }
 
     private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
-        recyclerView.bindFastScrollbar(mFastScroller);
+        recyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
         if (mCurrentWidgetsRecyclerView != recyclerView) {
             // Only reset the scroll position & expanded apps if the currently shown recycler view
             // has been updated.
@@ -290,10 +291,10 @@
     protected void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
         // The first item is always an empty space entry. Look for any more items.
         boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
-        adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
 
         if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
             mNoWidgetsView.setText(R.string.no_search_results);
+            adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
         } else if (adapterHolder.mAdapterType == AdapterHolder.WORK
                 && mUserCache.getUserProfiles().stream()
                 .filter(userHandle -> mUserCache.getUserInfo(userHandle).isWork())
@@ -556,6 +557,8 @@
             mNoWidgetsView.setVisibility(GONE);
         } else {
             mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+            mAdapters.get(getCurrentAdapterHolderType()).mWidgetsRecyclerView.setVisibility(
+                    VISIBLE);
             // Visibility of recommended widgets, recycler views and headers are handled in methods
             // below.
             post(this::onRecommendedWidgetsBound);
@@ -1057,7 +1060,7 @@
             mWidgetsRecyclerView.setClipToOutline(true);
             mWidgetsRecyclerView.setClipChildren(false);
             mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
-            mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
+            mWidgetsRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
             mWidgetsRecyclerView.setItemAnimator(isTwoPane() ? null : mWidgetsListItemAnimator);
             mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
             if (!isTwoPane()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index c2cd903..f4b99a0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Process;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -342,14 +343,9 @@
                 false);
         mSuggestedWidgetsHeader.setExpanded(true);
 
-        PackageItemInfo packageItemInfo = new PackageItemInfo(
+        PackageItemInfo packageItemInfo = new HighresPackageItemInfo(
                 /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
-                Process.myUserHandle()) {
-            @Override
-            public boolean usingLowResIcon() {
-                return false;
-            }
-        };
+                Process.myUserHandle());
         String suggestionsHeaderTitle = getContext().getString(
                 R.string.suggested_widgets_header_title);
         String suggestionsRightPaneTitle = getContext().getString(
@@ -376,17 +372,14 @@
             mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
             final boolean isChangingHeaders = mSelectedHeader == null
                     || !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
-            // If the initial focus view is still focused, it is likely a programmatic header
-            // click.
-            if (mSelectedHeader != null
-                    && !getAccessibilityInitialFocusView().isAccessibilityFocused()) {
-                post(() -> {
-                    mRightPaneScrollView.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
-                    mRightPaneScrollView.performAccessibilityAction(
-                            AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
-                });
-            }
             if (isChangingHeaders)  {
+                // If the initial focus view is still focused or widget picker is still opening, it
+                // is likely a programmatic header click.
+                if (mSelectedHeader != null && !mOpenCloseAnimation.getAnimationPlayer().isRunning()
+                        && !getAccessibilityInitialFocusView().isAccessibilityFocused()) {
+                    mRightPaneScrollView.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
+                    focusOnFirstWidgetCell(mWidgetRecommendationsView);
+                }
                 // If switching from another header, unselect any WidgetCells. This is necessary
                 // because we do not clear/recycle the WidgetCells in the recommendations container
                 // when the header is clicked, only when onRecommendationsBound is called. That
@@ -464,6 +457,13 @@
         if (!isWidgetAvailable) {
             mRightPane.removeAllViews();
             mRightPane.addView(mNoWidgetsView);
+            // with no widgets message, no header is selected on left
+            if (mSuggestedWidgetsPackageUserKey != null
+                    && mSuggestedWidgetsPackageUserKey.equals(mSelectedHeader)
+                    && mSuggestedWidgetsHeader != null) {
+                mSuggestedWidgetsHeader.setExpanded(false);
+            }
+            mSelectedHeader = null;
         }
         super.updateRecyclerViewVisibility(adapterHolder);
     }
@@ -505,9 +505,10 @@
             public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
                 final boolean isSameHeader = mSelectedHeader != null
                         && mSelectedHeader.equals(selectedHeader);
-                // If the initial focus view is still focused, it is likely a programmatic header
-                // click.
+                // If the initial focus view is still focused or widget picker is still opening, it
+                // is likely a programmatic header click.
                 final boolean isUserClick = mSelectedHeader != null
+                        && !mOpenCloseAnimation.getAnimationPlayer().isRunning()
                         && !getAccessibilityInitialFocusView().isAccessibilityFocused();
                 mSelectedHeader = selectedHeader;
                 final boolean showDefaultWidgets = mWidgetOptionsMenuState != null
@@ -659,4 +660,15 @@
          */
         public boolean showAllWidgets = false;
     }
+
+    private static class HighresPackageItemInfo extends PackageItemInfo {
+        HighresPackageItemInfo(String packageName, UserHandle user) {
+            super(packageName, user);
+        }
+
+        @Override
+        public boolean usingLowResIcon() {
+            return false;
+        }
+    }
 }
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..4d7f937
--- /dev/null
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.dagger;
+
+import dagger.Component;
+
+import javax.inject.Singleton;
+
+/**
+ * Root component for Dagger injection for Launcher AOSP.
+ */
+@Singleton
+@Component
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+    /** Builder for aosp LauncherAppComponent. */
+    @Component.Builder
+    interface Builder extends LauncherBaseAppComponent.Builder {
+        LauncherAppComponent build();
+    }
+}
+
diff --git a/tests/Android.bp b/tests/Android.bp
index c99f656..9f62d02 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -127,9 +127,9 @@
         "com_android_launcher3_flags_lib",
     ],
     libs: [
-        "android.test.base",
-        "android.test.runner",
-        "android.test.mock",
+        "android.test.base.stubs.system",
+        "android.test.runner.stubs.system",
+        "android.test.mock.stubs.system",
     ],
     // Libraries used by mockito inline extended
     jni_libs: [
@@ -160,7 +160,7 @@
 }
 
 filegroup {
-    name: "launcher-testing-helpers",
+    name: "launcher-testing-helpers-robo",
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
@@ -174,11 +174,20 @@
         // Test classes
         "src/**/*Test.java",
         "src/**/*Test.kt",
+        "src/**/RoboApiWrapper.kt",
         "multivalentTests/src/**/*Test.java",
         "multivalentTests/src/**/*Test.kt",
     ],
 }
 
+filegroup {
+    name: "launcher-testing-helpers",
+    srcs: [
+        ":launcher-testing-helpers-robo",
+        "src/**/RoboApiWrapper.kt",
+    ],
+}
+
 android_robolectric_test {
     enabled: true,
     name: "Launcher3RoboTests",
@@ -186,7 +195,7 @@
         ":launcher3-robo-src",
 
         // Test util classes
-        ":launcher-testing-helpers",
+        ":launcher-testing-helpers-robo",
         ":launcher-testing-shared",
     ],
     exclude_srcs: [
@@ -220,9 +229,9 @@
         "android.appwidget.flags-aconfig-java",
     ],
     libs: [
-        "android.test.runner",
-        "android.test.base",
-        "android.test.mock",
+        "android.test.runner.stubs.system",
+        "android.test.base.stubs.system",
+        "android.test.mock.stubs.system",
         "truth",
     ],
     instrumentation_for: "Launcher3",
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index a20b0f1..ea58136 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -171,7 +171,6 @@
     public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
     public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
     public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
-    public static final String OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH = "b/336660988";
     public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
     public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index 30953cc..a62258c 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -17,6 +17,9 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -37,6 +40,8 @@
 import com.android.launcher3.celllayout.testgenerator.RandomBoardGenerator;
 import com.android.launcher3.celllayout.testgenerator.RandomMultiBoardGenerator;
 import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
 
 import org.junit.Rule;
@@ -68,12 +73,16 @@
     private Context mApplicationContext;
 
     @Rule
+    public TestStabilityRule mTestStabilityRule = new TestStabilityRule();
+
+    @Rule
     public UnitTestCellLayoutBuilderRule mCellLayoutBuilder = new UnitTestCellLayoutBuilderRule();
 
     /**
      * This test reads existing test cases and makes sure the CellLayout produces the same
      * output for each of them for a given input.
      */
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     public void testAllCases() throws IOException {
         List<ReorderAlgorithmUnitTestCase> testCases = getTestCases(
@@ -116,6 +125,7 @@
     /**
      * Same as above but testing the Multipage CellLayout.
      */
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     public void generateValidTests_Multi() {
         Random generator = new Random(SEED);
diff --git a/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
index 7242e9c..b9b7d6a 100644
--- a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -24,15 +24,15 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.PathInterpolator;
 
+import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.launcher3.CellLayout;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -41,8 +41,8 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@UiThreadTest
+@RunWith(LauncherMultivalentJUnit.class)
 public class PreviewBackgroundTest {
 
     private static final float REST_SCALE = 1f;
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 7c9f99a..d236551 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -29,6 +29,7 @@
 import com.android.launcher3.icons.BaseIconFactory
 import com.android.launcher3.icons.FastBitmapDrawable
 import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.model.ModelTestRule
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED
@@ -44,6 +45,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -52,6 +54,8 @@
 @RunWith(AndroidJUnit4::class)
 class PreviewItemManagerTest {
 
+    @get:Rule val modelTestRule = ModelTestRule()
+
     private lateinit var previewItemManager: PreviewItemManager
     private lateinit var context: Context
     private lateinit var folderItems: ArrayList<ItemInfo>
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 370af0c..43dc36b 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -27,6 +27,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.times
@@ -43,6 +44,8 @@
 @RunWith(AndroidJUnit4::class)
 class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
 
+    @get:Rule val modelTestRule = ModelTestRule()
+
     private lateinit var mDataModelCallbacks: MyCallbacks
 
     private val mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder = mock()
diff --git a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
similarity index 99%
rename from tests/src/com/android/launcher3/model/AsyncBindingTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
index af367a8..dce75b9 100644
--- a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
@@ -64,6 +64,8 @@
 
     @get:Rule val setFlagsRule = SetFlagsRule()
 
+    @get:Rule val modelTestRule = ModelTestRule()
+
     @Spy private var callbacks = MyCallbacks()
     @Mock private lateinit var itemInflater: ItemInflater<*>
 
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
similarity index 84%
rename from tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 328558d..535080a 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2024 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.model;
 
 import static android.os.Process.myUserHandle;
@@ -11,10 +26,13 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.content.pm.PackageInstaller;
 
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -49,6 +67,9 @@
     @Rule(order = 0)
     public TestRule testStabilityRule = new TestStabilityRule();
 
+    @Rule(order = 1)
+    public ModelTestRule mModelTestRule = new ModelTestRule();
+
     private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
     private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
 
@@ -128,10 +149,13 @@
     @Test
     public void testSessionUpdate_updates_pending_apps() {
         // Run on model executor so that no other task runs in the middle.
+        PackageInstaller.SessionInfo sessionInfo = ApplicationProvider.getApplicationContext()
+                        .getPackageManager().getPackageInstaller().getSessionInfo(mSession1);
+        assertNotNull(sessionInfo);
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
             LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
                     new PackageUserKey(PENDING_APP_1, myUserHandle()),
-                    mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession1));
+                    sessionInfo);
 
             // Clear all icons from apps list so that its easy to check what was updated
             allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
similarity index 93%
rename from tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 10785f7..e14e145 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -22,11 +22,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
-import android.content.Context;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionParams;
 
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -39,6 +39,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,8 +50,10 @@
 @RunWith(AndroidJUnit4.class)
 public class DefaultLayoutProviderTest {
 
+    @Rule public ModelTestRule rule = new ModelTestRule();
+
     private LauncherModelHelper mModelHelper;
-    private Context mTargetContext;
+    private LauncherModelHelper.SandboxModelContext mTargetContext;
 
     @Before
     public void setUp() {
@@ -114,8 +117,10 @@
         SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
         params.setAppPackageName(pendingAppPkg);
         params.setAppIcon(BitmapInfo.LOW_RES_ICON);
+        params.installerPackageName = ApplicationProvider.getApplicationContext().getPackageName();
 
-        PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
+        PackageInstaller installer = ApplicationProvider.getApplicationContext().getPackageManager()
+                .getPackageInstaller();
         installer.createSession(params);
 
         writeLayoutAndLoad(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
diff --git a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
index aadf72e..d2d9512 100644
--- a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
@@ -21,6 +21,7 @@
 import android.content.Intent
 import android.content.pm.PackageInstaller.SessionInfo
 import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
@@ -33,14 +34,20 @@
 import com.android.launcher3.util.PackageManagerHelper
 import com.android.launcher3.util.PackageUserKey
 import junit.framework.Assert.assertEquals
+import org.junit.Rule
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
+@RunWith(AndroidJUnit4::class)
 class FirstScreenBroadcastHelperTest {
+
+    @get:Rule val modelTestRule = ModelTestRule()
+
     private val context = spy(InstrumentationRegistry.getInstrumentation().targetContext)
     private val mockPmHelper = mock<PackageManagerHelper>()
     private val expectedAppPackage = "appPackageExpected"
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
similarity index 96%
rename from tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index c4a4c9b..d002493 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -23,12 +23,14 @@
 import com.android.launcher3.util.LauncherLayoutBuilder
 import com.android.launcher3.util.LauncherModelHelper
 import com.android.launcher3.util.LauncherModelHelper.*
+import com.android.launcher3.util.RoboApiWrapper
 import com.android.launcher3.util.TestUtil
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.CountDownLatch
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -36,6 +38,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class FolderIconLoadTest {
+
+    @get:Rule(order = 0) val modelTestRule = ModelTestRule()
+
     private lateinit var modelHelper: LauncherModelHelper
 
     private val uniqueActivities =
@@ -145,6 +150,7 @@
         while (cache.isIconUpdateInProgress) {
             val wait = CountDownLatch(1)
             Executors.MODEL_EXECUTOR.handler.postDelayed({ wait.countDown() }, 10)
+            RoboApiWrapper.waitForLooperSync(Executors.MODEL_EXECUTOR.handler.looper)
             wait.await()
         }
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { cache.clearMemoryCache() }
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/model/LoaderCursorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index b4945d7..ac911b3 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -67,6 +67,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -77,6 +78,8 @@
 @RunWith(AndroidJUnit4.class)
 public class LoaderCursorTest {
 
+    @Rule public ModelTestRule rule = new ModelTestRule();
+
     private LauncherModelHelper mModelHelper;
     private LauncherAppState mApp;
     private PackageManagerHelper mPmHelper;
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt
new file mode 100644
index 0000000..ad2c2a4
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.model
+
+import com.android.launcher3.util.RoboApiWrapper
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+class ModelTestRule : TestWatcher() {
+    override fun starting(description: Description?) {
+        RoboApiWrapper.initialize()
+    }
+}
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
similarity index 87%
rename from tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 4ba61ac..a0d9da9 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2024 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.model;
 
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -22,6 +37,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -32,6 +48,8 @@
 @RunWith(AndroidJUnit4.class)
 public class PackageInstallStateChangedTaskTest {
 
+    @Rule public ModelTestRule mModelTestRule = new ModelTestRule();
+
     private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
     private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
 
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
similarity index 81%
rename from tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 6cf3b19..1d9c161 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -25,10 +25,9 @@
 import android.content.pm.ShortcutInfo
 import android.os.Process
 import android.os.UserHandle
-import android.platform.test.annotations.EnableFlags
 import android.util.LongSparseArray
-import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
@@ -36,7 +35,6 @@
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
-import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
@@ -46,7 +44,6 @@
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
-import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
 import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.pm.UserCache
@@ -57,11 +54,12 @@
 import com.android.launcher3.util.UserIconInfo
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
 import com.android.launcher3.widget.WidgetInflater
-import com.android.launcher3.widget.WidgetSections
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.RETURNS_DEEP_STUBS
@@ -74,10 +72,12 @@
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
-import org.mockito.quality.Strictness
 
+@RunWith(AndroidJUnit4::class)
 class WorkspaceItemProcessorTest {
 
+    @get:Rule val modelTestRule = ModelTestRule()
+
     @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
     @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
     @Mock private lateinit var mockBgDataModel: BgDataModel
@@ -122,6 +122,7 @@
             mock<Context>().apply {
                 whenever(packageManager).thenReturn(mock())
                 whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+                whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
             }
         mockAppState =
             mock<LauncherAppState>().apply {
@@ -666,142 +667,6 @@
     }
 
     @Test
-    fun `When Pending App Widget has not started restore then update db and add item`() {
-
-        val mockitoSession =
-            ExtendedMockito.mockitoSession()
-                .strictness(Strictness.LENIENT)
-                .mockStatic(WidgetSections::class.java)
-                .startMocking()
-        try {
-            // Given
-            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
-            val expectedComponentName =
-                ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
-            val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
-            val expectedAppWidgetId = 0
-            mockCursor.apply {
-                itemType = ITEM_TYPE_APPWIDGET
-                user = mUserHandle
-                restoreFlag = FLAG_UI_NOT_READY
-                container = CONTAINER_DESKTOP
-                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
-                whenever(appWidgetProvider).thenReturn(expectedProvider)
-                whenever(appWidgetId).thenReturn(expectedAppWidgetId)
-                whenever(spanX).thenReturn(2)
-                whenever(spanY).thenReturn(1)
-                whenever(options).thenReturn(0)
-                whenever(appWidgetSource).thenReturn(20)
-                whenever(applyCommonProperties(any())).thenCallRealMethod()
-                whenever(
-                        updater()
-                            .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
-                            .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
-                            .put(Favorites.RESTORED, expectedRestoreStatus)
-                            .commit()
-                    )
-                    .thenReturn(1)
-            }
-            val inflationResult =
-                WidgetInflater.InflationResult(
-                    type = WidgetInflater.TYPE_PENDING,
-                    widgetInfo = null
-                )
-            mockWidgetInflater =
-                mock<WidgetInflater>().apply {
-                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
-                }
-            val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
-            mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
-
-            // When
-            itemProcessorUnderTest =
-                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
-            itemProcessorUnderTest.processItem()
-
-            // Then
-            val expectedWidgetInfo =
-                LauncherAppWidgetInfo().apply {
-                    appWidgetId = expectedAppWidgetId
-                    providerName = ComponentName.unflattenFromString(expectedProvider)
-                    restoreStatus = expectedRestoreStatus
-                }
-            verify(
-                    mockCursor
-                        .updater()
-                        .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
-                        .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
-                        .put(Favorites.RESTORED, expectedRestoreStatus)
-                )
-                .commit()
-            val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
-            verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
-            val actualWidgetInfo = widgetInfoCaptor.value
-            with(actualWidgetInfo) {
-                assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
-                assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
-                assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
-                assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
-            }
-        } finally {
-            mockitoSession.finishMocking()
-        }
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
-    fun `When Archived Pending App Widget then checkAndAddItem`() {
-        val mockitoSession =
-            ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
-        try {
-            // Given
-            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
-            val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
-            val expectedPackage = expectedComponentName!!.packageName
-            mockPmHelper =
-                mock<PackageManagerHelper>().apply {
-                    whenever(isAppArchived(expectedPackage)).thenReturn(true)
-                }
-            mockCursor =
-                mock<LoaderCursor>().apply {
-                    itemType = ITEM_TYPE_APPWIDGET
-                    id = 1
-                    user = UserHandle(1)
-                    restoreFlag = FLAG_UI_NOT_READY
-                    container = CONTAINER_DESKTOP
-                    whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
-                    whenever(appWidgetProvider).thenReturn(expectedProvider)
-                    whenever(appWidgetId).thenReturn(0)
-                    whenever(spanX).thenReturn(2)
-                    whenever(spanY).thenReturn(1)
-                    whenever(options).thenReturn(0)
-                    whenever(appWidgetSource).thenReturn(20)
-                    whenever(applyCommonProperties(any())).thenCallRealMethod()
-                }
-            mInstallingPkgs = hashMapOf()
-            val inflationResult =
-                WidgetInflater.InflationResult(
-                    type = WidgetInflater.TYPE_PENDING,
-                    widgetInfo = null
-                )
-            mockWidgetInflater =
-                mock<WidgetInflater>().apply {
-                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
-                }
-            itemProcessorUnderTest =
-                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
-
-            // When
-            itemProcessorUnderTest.processItem()
-
-            // Then
-            verify(mockCursor).checkAndAddItem(any(), any())
-        } finally {
-            mockitoSession.finishMocking()
-        }
-    }
-
-    @Test
     fun `When widget inflation result is TYPE_DELETE then mark deleted`() {
         // Given
         val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index b3d02be..ae8e966 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -21,6 +21,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -29,6 +30,8 @@
 @RunWith(AndroidJUnit4::class)
 class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
 
+    @get:Rule val modelTestRule = ModelTestRule()
+
     private val mItemSpaceFinder = WorkspaceItemSpaceFinder()
 
     @Before
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
index b531adb..d860710 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
@@ -26,6 +26,7 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
 import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import com.android.launcher3.model.ModelTestRule
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
 import com.android.launcher3.util.LauncherModelHelper
 import com.android.launcher3.util.PackageUserKey
@@ -35,6 +36,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.any
+import org.mockito.kotlin.doNothing
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
@@ -43,7 +45,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class InstallSessionTrackerTest {
-    @get:Rule val setFlagsRule = SetFlagsRule()
+    @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+
+    @get:Rule(order = 1) val modelTestRule = ModelTestRule()
 
     private val mockInstallSessionHelper: InstallSessionHelper = mock()
     private val mockCallback: InstallSessionTracker.Callback = mock()
@@ -200,13 +204,9 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     fun `register triggers registerPackageInstallerSessionCallback for versions from Q`() {
         // Given
-        whenever(
-                launcherApps.registerPackageInstallerSessionCallback(
-                    MODEL_EXECUTOR,
-                    installSessionTracker
-                )
-            )
-            .then { /* no-op */ }
+        doNothing()
+            .whenever(launcherApps)
+            .registerPackageInstallerSessionCallback(MODEL_EXECUTOR, installSessionTracker)
         // When
         installSessionTracker.register()
         // Then
@@ -218,8 +218,9 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     fun `unregister triggers unregisterPackageInstallerSessionCallback for versions from Q`() {
         // Given
-        whenever(launcherApps.unregisterPackageInstallerSessionCallback(installSessionTracker))
-            .then { /* no-op */ }
+        doNothing()
+            .whenever(launcherApps)
+            .unregisterPackageInstallerSessionCallback(installSessionTracker)
         // When
         installSessionTracker.unregister()
         // Then
diff --git a/tests/src/com/android/launcher3/pm/UserCacheTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/pm/UserCacheTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
index b21219e..482dced 100644
--- a/tests/src/com/android/launcher3/pm/UserCacheTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
@@ -20,6 +20,7 @@
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.model.ModelTestRule
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
 import com.android.launcher3.util.LauncherModelHelper
 import com.android.launcher3.util.TestUtil
@@ -27,11 +28,15 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 class UserCacheTest {
+
+    @get:Rule val modelTestRule = ModelTestRule()
+
     private val launcherModelHelper = LauncherModelHelper()
     private val sandboxContext = launcherModelHelper.sandboxContext
     private lateinit var userCache: UserCache
diff --git a/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java b/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
deleted file mode 100644
index 10e0be8..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2021 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.settings;
-
-import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT;
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
-import static androidx.test.espresso.intent.Intents.intended;
-import static androidx.test.espresso.intent.matcher.BundleMatchers.hasEntry;
-import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
-import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-
-import static com.android.launcher3.settings.SettingsActivity.DEVELOPER_OPTIONS_KEY;
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARGS;
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ROOT_KEY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.equalTo;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.espresso.intent.Intents;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.launcher3.R;
-import com.android.systemui.shared.plugins.PluginPrefs;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class SettingsActivityTest {
-
-    private Context mApplicationContext;
-
-    @Before
-    public void setUp() {
-        mApplicationContext = ApplicationProvider.getApplicationContext();
-        Intents.init();
-    }
-
-    @After
-    public void tearDown() {
-        Intents.release();
-    }
-
-    @Test
-    @Ignore  // b/199309785
-    public void testSettings_aboutTap_launchesActivity() {
-        ActivityScenario.launch(SettingsActivity.class);
-        onView(withId(R.id.recycler_view)).perform(
-                actionOnItem(hasDescendant(withText("About")), click()));
-
-        intended(allOf(
-                hasComponent(SettingsActivity.class.getName()),
-                hasExtra(
-                        equalTo(EXTRA_FRAGMENT_ARGS),
-                        hasEntry(ARG_PREFERENCE_ROOT, "about_screen"))));
-    }
-
-    @Test
-    @Ignore  // b/199309785
-    public void testSettings_developerOptionsTap_launchesActivityWithFragment() {
-        PluginPrefs.setHasPlugins(mApplicationContext);
-        ActivityScenario.launch(SettingsActivity.class);
-        onView(withId(R.id.recycler_view)).perform(
-                actionOnItem(hasDescendant(withText("Developer Options")), click()));
-
-        intended(allOf(
-                hasComponent(SettingsActivity.class.getName()),
-                hasExtra(EXTRA_FRAGMENT_ROOT_KEY, DEVELOPER_OPTIONS_KEY)));
-    }
-
-    @Test
-    @Ignore  // b/199309785
-    public void testSettings_aboutScreenIntent() {
-        Bundle fragmentArgs = new Bundle();
-        fragmentArgs.putString(ARG_PREFERENCE_ROOT, "about_screen");
-
-        Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
-                .putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs);
-        ActivityScenario.launch(intent);
-
-        onView(withText("About")).check(matches(isDisplayed()));
-        onView(withText("Version")).check(matches(isDisplayed()));
-        onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
-    }
-
-    @Test
-    @Ignore  // b/199309785
-    public void testSettings_developerOptionsFragmentIntent() {
-        Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
-                .putExtra(EXTRA_FRAGMENT_ROOT_KEY, DEVELOPER_OPTIONS_KEY);
-        ActivityScenario.launch(intent);
-
-        onView(withText("Developer Options")).check(matches(isDisplayed()));
-        onView(withId(R.id.filter_box)).check(matches(isDisplayed()));
-        onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
-    }
-
-    @Test
-    @Ignore  // b/199309785
-    public void testSettings_backButtonFinishesActivity() {
-        Bundle fragmentArgs = new Bundle();
-        fragmentArgs.putString(ARG_PREFERENCE_ROOT, "about_screen");
-        Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
-                .putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs);
-        ActivityScenario<SettingsActivity> scenario = ActivityScenario.launch(intent);
-
-        onView(withContentDescription("Navigate up")).perform(click());
-        scenario.onActivity(activity -> assertThat(activity.isFinishing()).isTrue());
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index aa7f388..b933ed2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
 import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT;
 import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_SMALL;
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
 import static com.android.launcher3.Flags.FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS;
 import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
@@ -416,7 +417,7 @@
         assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(false);
     }
 
-    @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
+    @EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS})
     @Test
     public void applyIconAndLabel_setsImageSpan_whenInactiveArchivedApp() {
         // Given
@@ -452,7 +453,7 @@
         assertThat(actualSpan.getVerticalAlignment()).isEqualTo(ALIGN_CENTER);
     }
 
-    @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
+    @EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS})
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
     public void applyIconAndLabel_setsBoldDrawable_whenBoldedTextForArchivedApp() {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index f18c02b..2d53e29 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -45,21 +45,24 @@
 import android.util.ArrayMap;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.uiautomator.UiDevice;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.testing.TestInformationProvider;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.util.Arrays;
+import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -85,6 +88,23 @@
     public static final String TEST_ACTIVITY13 = "com.android.launcher3.tests.Activity14";
     public static final String TEST_ACTIVITY14 = "com.android.launcher3.tests.Activity15";
 
+    public static final List<String> ACTIVITY_LIST = Arrays.asList(
+            TEST_ACTIVITY,
+            TEST_ACTIVITY2,
+            TEST_ACTIVITY3,
+            TEST_ACTIVITY4,
+            TEST_ACTIVITY5,
+            TEST_ACTIVITY6,
+            TEST_ACTIVITY7,
+            TEST_ACTIVITY8,
+            TEST_ACTIVITY9,
+            TEST_ACTIVITY10,
+            TEST_ACTIVITY11,
+            TEST_ACTIVITY12,
+            TEST_ACTIVITY13,
+            TEST_ACTIVITY14
+    );
+
     // Authority for providing a test default-workspace-layout data.
     private static final String TEST_PROVIDER_AUTHORITY =
             LauncherModelHelper.class.getName().toLowerCase();
@@ -128,7 +148,9 @@
         icon.eraseColor(Color.RED);
         sp.setAppIcon(icon);
         sp.setAppLabel(pkg);
-        PackageInstaller pi = sandboxContext.getPackageManager().getPackageInstaller();
+        sp.setInstallerPackageName(ApplicationProvider.getApplicationContext().getPackageName());
+        PackageInstaller pi = ApplicationProvider.getApplicationContext().getPackageManager()
+                .getPackageInstaller();
         int sessionId = pi.createSession(sp);
         mDestroyTask.add(() -> pi.abandonSession(sessionId));
         return sessionId;
@@ -164,11 +186,19 @@
     public LauncherModelHelper setupDefaultLayoutProvider(LauncherLayoutBuilder builder)
             throws Exception {
         InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(sandboxContext);
-        idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
-        idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
+        if (idp.numRows == 0 && idp.numColumns == 0) {
+            idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
+        }
+        if (idp.iconBitmapSize == 0) {
+            idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
+        }
 
-        UiDevice.getInstance(getInstrumentation()).executeShellCommand(
-                "settings put secure launcher3.layout.provider " + TEST_PROVIDER_AUTHORITY);
+        Settings.Secure.putString(sandboxContext.getContentResolver(), "launcher3.layout.provider",
+                TEST_PROVIDER_AUTHORITY);
+
+        // TODO: use a wrapper class to differentiate the behavior
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        builder.build(new OutputStreamWriter(bos));
         ContentProvider cp = new TestInformationProvider() {
 
             @Override
@@ -177,8 +207,6 @@
                 try {
                     ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
                     AutoCloseOutputStream outputStream = new AutoCloseOutputStream(pipe[1]);
-                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-                    builder.build(new OutputStreamWriter(bos));
                     outputStream.write(bos.toByteArray());
                     outputStream.flush();
                     outputStream.close();
@@ -189,9 +217,13 @@
             }
         };
         setupProvider(TEST_PROVIDER_AUTHORITY, cp);
+        RoboApiWrapper.INSTANCE.registerInputStream(sandboxContext.getContentResolver(),
+                ModelDbController.getLayoutUri(TEST_PROVIDER_AUTHORITY, sandboxContext),
+                ()-> new ByteArrayInputStream(bos.toByteArray()));
+
         mDestroyTask.add(() -> runOnExecutorSync(MODEL_EXECUTOR, () ->
-                UiDevice.getInstance(getInstrumentation()).executeShellCommand(
-                        "settings delete secure launcher3.layout.provider")));
+                Settings.Secure.putString(sandboxContext.getContentResolver(),
+                        "launcher3.layout.provider", "")));
         return this;
     }
 
@@ -203,7 +235,7 @@
         MAIN_EXECUTOR.submit(() -> getModel().addCallbacksAndLoad(mockCb)).get();
 
         Executors.MODEL_EXECUTOR.submit(() -> { }).get();
-        MAIN_EXECUTOR.submit(() -> { }).get();
+        getInstrumentation().waitForIdleSync();
         MAIN_EXECUTOR.submit(() -> getModel().removeCallbacks(mockCb)).get();
     }
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
index 330c394..d321e41 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
@@ -17,7 +17,6 @@
 package com.android.launcher3.util
 
 import android.media.AudioAttributes
-import android.os.SystemClock
 import android.os.VibrationEffect
 import android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK
 import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
@@ -35,13 +34,11 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.any
-import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.never
 import org.mockito.kotlin.same
-import org.mockito.kotlin.verifyNoMoreInteractions
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -118,55 +115,6 @@
     }
 
     @Test
-    fun vibrate_for_drag_bump() {
-        underTest.vibrateForDragBump()
-
-        awaitTasksCompleted()
-        verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
-        val expectedEffect =
-            VibrationEffect.startComposition()
-                .addPrimitive(PRIMITIVE_LOW_TICK, VibratorWrapper.DRAG_BUMP_SCALE)
-                .compose()
-        assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
-    }
-
-    @Test
-    fun vibrate_for_drag_commit() {
-        underTest.vibrateForDragCommit()
-
-        awaitTasksCompleted()
-        verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
-        val expectedEffect =
-            VibrationEffect.startComposition()
-                .addPrimitive(PRIMITIVE_TICK, VibratorWrapper.DRAG_COMMIT_SCALE)
-                .compose()
-        assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
-    }
-
-    @Test
-    fun vibrate_for_drag_texture() {
-        SystemClock.setCurrentTimeMillis(40000)
-
-        underTest.vibrateForDragTexture()
-
-        awaitTasksCompleted()
-        verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
-        assertThat(vibrationEffectCaptor.value).isEqualTo(VibratorWrapper.getDragEffect())
-    }
-
-    @Test
-    fun vibrate_for_drag_texture_within_time_window_noOp() {
-        SystemClock.setCurrentTimeMillis(40000)
-        underTest.vibrateForDragTexture()
-        awaitTasksCompleted()
-        reset(vibrator)
-
-        underTest.vibrateForDragTexture()
-
-        verifyNoMoreInteractions(vibrator)
-    }
-
-    @Test
     fun haptic_feedback_disabled_no_vibrate() {
         `when`(vibrator.hasVibrator()).thenReturn(false)
         underTest = VibratorWrapper(vibrator, settingsCache)
diff --git a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
similarity index 86%
rename from tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
index 011d138..d26c4d4 100644
--- a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
@@ -32,7 +32,7 @@
 import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.reset
 import org.mockito.kotlin.same
-import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.verifyNoMoreInteractions
 
 @RunWith(AndroidJUnit4::class)
 class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
@@ -77,8 +77,8 @@
         underTest.attachTo(launcher)
 
         verify(workspace).addOnAttachStateChangeListener(same(underTest))
-        verifyZeroInteractions(viewTreeObserver)
-        verifyZeroInteractions(rootView)
+        verifyNoMoreInteractions(viewTreeObserver)
+        verifyNoMoreInteractions(rootView)
     }
 
     @Test
@@ -100,8 +100,8 @@
 
         underTest.onViewAttachedToWindow(rootView)
 
-        verifyZeroInteractions(viewTreeObserver)
-        verifyZeroInteractions(rootView)
+        verifyNoMoreInteractions(viewTreeObserver)
+        verifyNoMoreInteractions(rootView)
     }
 
     @Test
@@ -117,10 +117,10 @@
     fun run_before_onDraw_noOp() {
         underTest.run()
 
-        verifyZeroInteractions(runnable)
-        verifyZeroInteractions(viewTreeObserver)
-        verifyZeroInteractions(workspace)
-        verifyZeroInteractions(consumer)
+        verifyNoMoreInteractions(runnable)
+        verifyNoMoreInteractions(viewTreeObserver)
+        verifyNoMoreInteractions(workspace)
+        verifyNoMoreInteractions(consumer)
     }
 
     @Test
@@ -148,10 +148,10 @@
 
         underTest.run()
 
-        verifyZeroInteractions(runnable)
-        verifyZeroInteractions(viewTreeObserver)
-        verifyZeroInteractions(workspace)
-        verifyZeroInteractions(consumer)
+        verifyNoMoreInteractions(runnable)
+        verifyNoMoreInteractions(viewTreeObserver)
+        verifyNoMoreInteractions(workspace)
+        verifyNoMoreInteractions(consumer)
     }
 
     @Test
@@ -160,7 +160,7 @@
 
         verify(runnable).run()
         verify(consumer).accept(underTest)
-        verifyZeroInteractions(workspace)
+        verifyNoMoreInteractions(workspace)
     }
 
     @Test
@@ -179,8 +179,8 @@
     fun cancel_notRun() {
         underTest.cancel()
 
-        verifyZeroInteractions(runnable)
+        verifyNoMoreInteractions(runnable)
         verify(consumer).accept(underTest)
-        verifyZeroInteractions(workspace)
+        verifyNoMoreInteractions(workspace)
     }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index 909aabd..ad2d8c2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -109,6 +109,9 @@
                     getPackageManager().
                     getPackageInfo(launcherPackageName, 0)
                     .versionName;
+            if (launcherVersion == null) {
+                return LOCAL;
+            }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(e);
         }
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 05a1224..c7c9dbb 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.platform.test.annotations.PlatinumTest;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.launcher3.Launcher;
@@ -33,7 +32,6 @@
 import com.android.launcher3.tapl.AllApps;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule;
 
 import org.junit.Test;
 
@@ -191,7 +189,6 @@
     /**
      * Makes sure that when pressing back when AllApps is open we go back to the Home screen.
      */
-    @FlakyTest(bugId = 256615483)
     @Test
     @PortraitLandscape
     public void testPressBackFromAllAppsToHome() {
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
index 4cecb5a..bcb9191 100644
--- a/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
@@ -21,6 +21,7 @@
 import android.view.View
 import android.view.ViewGroup
 import com.android.launcher3.CellLayout
+import com.android.launcher3.Utilities
 import com.android.launcher3.Workspace
 import com.android.launcher3.util.CellAndSpan
 import com.android.launcher3.widget.LauncherAppWidgetHostView
@@ -54,7 +55,7 @@
         return view as LauncherAppWidgetHostView
     }
 
-    fun getCellTopLeftRelativeToCellLayout(
+    fun getCellTopLeftRelativeToWorkspace(
         workspace: Workspace<*>,
         cellAndSpan: CellAndSpan
     ): Point {
@@ -67,6 +68,8 @@
             cellAndSpan.spanY,
             target
         )
-        return Point(target.left, target.top)
+        val point = floatArrayOf(target.left.toFloat(), target.top.toFloat())
+        Utilities.getDescendantCoordRelativeToAncestor(cellLayout, workspace, point, false)
+        return Point(point[0].toInt(), point[1].toInt())
     }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
index 365ad4b..5e062d0 100644
--- a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
@@ -35,9 +35,10 @@
 
     companion object {
         private const val TAG = "EventWaiter"
+        private val SIGNAL_TIMEOUT = TimeUnit.SECONDS.toMillis(5)
     }
 
-    fun waitForSignal(timeout: Long = TimeUnit.SECONDS.toMillis(10)) = runBlocking {
+    fun waitForSignal(timeout: Long = SIGNAL_TIMEOUT) = runBlocking {
         var status = withTimeoutOrNull(timeout) { deferrable.await() }
         if (status == null) {
             status = EventStatus.TIMEOUT
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 907aa50..7c87c65 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -98,7 +98,6 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/311099513
     public void testUninstallFromWorkspace() throws Exception {
         installDummyAppAndWaitForUIUpdate();
         try {
diff --git a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
index d9af07a..05f626d 100644
--- a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
@@ -58,7 +58,8 @@
 @RunWith(AndroidJUnit4::class)
 class PackageUpdatedTaskTest {
 
-    @get:Rule val setFlagsRule = SetFlagsRule()
+    @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+    @get:Rule(order = 1) val modelTestRule = ModelTestRule()
 
     private val mUser = UserHandle(0)
     private val mDataModel: BgDataModel = BgDataModel()
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
new file mode 100644
index 0000000..b93c305
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2024 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.model
+
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.util.LongSparseArray
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+import com.android.launcher3.Utilities
+import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.UserIconInfo
+import com.android.launcher3.widget.WidgetInflater
+import com.android.launcher3.widget.WidgetSections
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.RETURNS_DEEP_STUBS
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
+
+@RunWith(AndroidJUnit4::class)
+class WorkspaceItemProcessorExtraTest {
+
+    @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
+    @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
+    @Mock private lateinit var mockBgDataModel: BgDataModel
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var mockAppState: LauncherAppState
+    @Mock private lateinit var mockPmHelper: PackageManagerHelper
+    @Mock private lateinit var mockLauncherApps: LauncherApps
+    @Mock private lateinit var mockCursor: LoaderCursor
+    @Mock private lateinit var mockUserCache: UserCache
+    @Mock private lateinit var mockUserManagerState: UserManagerState
+    @Mock private lateinit var mockWidgetInflater: WidgetInflater
+
+    private var intent: Intent = Intent()
+    private var mUserHandle: UserHandle = UserHandle(0)
+    private var mIconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf()
+    private var mComponentName: ComponentName = ComponentName("package", "class")
+    private var mUnlockedUsersArray: LongSparseArray<Boolean> = LongSparseArray()
+    private var mKeyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo> = mutableMapOf()
+    private var mInstallingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf()
+    private var mAllDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+    private var mWidgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> =
+        mutableMapOf()
+    private var mPendingPackages: MutableSet<PackageUserKey> = mutableSetOf()
+
+    private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
+
+    @Before
+    fun setup() {
+        mUserHandle = UserHandle(0)
+        mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
+        mockWorkspaceInfo = mock<WorkspaceItemInfo>()
+        mockBgDataModel = mock<BgDataModel>()
+        mComponentName = ComponentName("package", "class")
+        mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+        intent =
+            Intent().apply {
+                component = mComponentName
+                `package` = "pkg"
+                putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
+            }
+        mockContext =
+            mock<Context>().apply {
+                whenever(packageManager).thenReturn(mock())
+                whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+                whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
+            }
+        mockAppState =
+            mock<LauncherAppState>().apply {
+                whenever(context).thenReturn(mockContext)
+                whenever(iconCache).thenReturn(mock())
+                whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
+            }
+        mockPmHelper =
+            mock<PackageManagerHelper>().apply {
+                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+                    .thenReturn(intent)
+            }
+        mockLauncherApps =
+            mock<LauncherApps>().apply {
+                whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+                whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
+            }
+        mockCursor =
+            Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
+                user = mUserHandle
+                itemType = ITEM_TYPE_APPLICATION
+                id = 1
+                restoreFlag = 1
+                serialNumber = 101
+                whenever(parseIntent()).thenReturn(intent)
+                whenever(markRestored()).doAnswer { restoreFlag = 0 }
+                whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
+                whenever(getAppShortcutInfo(any(), any(), any(), any()))
+                    .thenReturn(mockWorkspaceInfo)
+                whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
+            }
+        mockUserCache =
+            mock<UserCache>().apply {
+                val userIconInfo =
+                    mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
+                whenever(getUserInfo(any())).thenReturn(userIconInfo)
+            }
+
+        mockUserManagerState = mock<UserManagerState>()
+        mockWidgetInflater = mock<WidgetInflater>()
+        mKeyToPinnedShortcutsMap = mutableMapOf()
+        mInstallingPkgs = hashMapOf()
+        mAllDeepShortcuts = mutableListOf()
+        mWidgetProvidersMap = mutableMapOf()
+        mIconRequestInfos = mutableListOf()
+        mPendingPackages = mutableSetOf()
+    }
+
+    @Test
+    fun `When Pending App Widget has not started restore then update db and add item`() {
+
+        val mockitoSession =
+            ExtendedMockito.mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .mockStatic(WidgetSections::class.java)
+                .startMocking()
+        try {
+            // Given
+            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+            val expectedComponentName =
+                ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+            val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
+            val expectedAppWidgetId = 0
+            mockCursor.apply {
+                itemType = ITEM_TYPE_APPWIDGET
+                user = mUserHandle
+                restoreFlag = FLAG_UI_NOT_READY
+                container = CONTAINER_DESKTOP
+                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                whenever(appWidgetProvider).thenReturn(expectedProvider)
+                whenever(appWidgetId).thenReturn(expectedAppWidgetId)
+                whenever(spanX).thenReturn(2)
+                whenever(spanY).thenReturn(1)
+                whenever(options).thenReturn(0)
+                whenever(appWidgetSource).thenReturn(20)
+                whenever(applyCommonProperties(any())).thenCallRealMethod()
+                whenever(
+                        updater()
+                            .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
+                            .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+                            .put(Favorites.RESTORED, expectedRestoreStatus)
+                            .commit()
+                    )
+                    .thenReturn(1)
+            }
+            val inflationResult =
+                WidgetInflater.InflationResult(
+                    type = WidgetInflater.TYPE_PENDING,
+                    widgetInfo = null
+                )
+            mockWidgetInflater =
+                mock<WidgetInflater>().apply {
+                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+                }
+            val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
+            mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
+
+            // When
+            itemProcessorUnderTest =
+                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+            itemProcessorUnderTest.processItem()
+
+            // Then
+            val expectedWidgetInfo =
+                LauncherAppWidgetInfo().apply {
+                    appWidgetId = expectedAppWidgetId
+                    providerName = ComponentName.unflattenFromString(expectedProvider)
+                    restoreStatus = expectedRestoreStatus
+                }
+            verify(
+                    mockCursor
+                        .updater()
+                        .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
+                        .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+                        .put(Favorites.RESTORED, expectedRestoreStatus)
+                )
+                .commit()
+            val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
+            verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
+            val actualWidgetInfo = widgetInfoCaptor.value
+            with(actualWidgetInfo) {
+                assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
+                assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
+                assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
+                assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
+            }
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    fun `When Archived Pending App Widget then checkAndAddItem`() {
+        val mockitoSession =
+            ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
+        try {
+            // Given
+            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+            val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+            val expectedPackage = expectedComponentName!!.packageName
+            mockPmHelper =
+                mock<PackageManagerHelper>().apply {
+                    whenever(isAppArchived(expectedPackage)).thenReturn(true)
+                }
+            mockCursor =
+                mock<LoaderCursor>().apply {
+                    itemType = ITEM_TYPE_APPWIDGET
+                    id = 1
+                    user = UserHandle(1)
+                    restoreFlag = FLAG_UI_NOT_READY
+                    container = CONTAINER_DESKTOP
+                    whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                    whenever(appWidgetProvider).thenReturn(expectedProvider)
+                    whenever(appWidgetId).thenReturn(0)
+                    whenever(spanX).thenReturn(2)
+                    whenever(spanY).thenReturn(1)
+                    whenever(options).thenReturn(0)
+                    whenever(appWidgetSource).thenReturn(20)
+                    whenever(applyCommonProperties(any())).thenCallRealMethod()
+                }
+            mInstallingPkgs = hashMapOf()
+            val inflationResult =
+                WidgetInflater.InflationResult(
+                    type = WidgetInflater.TYPE_PENDING,
+                    widgetInfo = null
+                )
+            mockWidgetInflater =
+                mock<WidgetInflater>().apply {
+                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+                }
+            itemProcessorUnderTest =
+                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+            // When
+            itemProcessorUnderTest.processItem()
+
+            // Then
+            verify(mockCursor).checkAndAddItem(any(), any())
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    private fun createWorkspaceItemProcessorUnderTest(
+        cursor: LoaderCursor = mockCursor,
+        memoryLogger: LoaderMemoryLogger? = null,
+        userCache: UserCache = mockUserCache,
+        userManagerState: UserManagerState = mockUserManagerState,
+        launcherApps: LauncherApps = mockLauncherApps,
+        shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
+        app: LauncherAppState = mockAppState,
+        bgDataModel: BgDataModel = mockBgDataModel,
+        widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
+        widgetInflater: WidgetInflater = mockWidgetInflater,
+        pmHelper: PackageManagerHelper = mockPmHelper,
+        iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mIconRequestInfos,
+        isSdCardReady: Boolean = false,
+        pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
+        unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
+        installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
+        allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
+    ) =
+        WorkspaceItemProcessor(
+            c = cursor,
+            memoryLogger = memoryLogger,
+            userCache = userCache,
+            userManagerState = userManagerState,
+            launcherApps = launcherApps,
+            app = app,
+            bgDataModel = bgDataModel,
+            widgetProvidersMap = widgetProvidersMap,
+            widgetInflater = widgetInflater,
+            pmHelper = pmHelper,
+            unlockedUsers = unlockedUsers,
+            iconRequestInfos = iconRequestInfos,
+            pendingPackages = pendingPackages,
+            isSdCardReady = isSdCardReady,
+            shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
+            installingPkgs = installingPkgs,
+            allDeepShortcuts = allDeepShortcuts
+        )
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
similarity index 100%
rename from tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
rename to tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 749a75a..68004bb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -351,8 +351,6 @@
 
     /** Waits for setup wizard to go away. */
     private static void waitForSetupWizardDismissal() {
-        if (!TestStabilityRule.isPresubmit()) return;
-
         if (sFirstTimeWaitingForWizard) {
             try {
                 getUiDevice().executeShellCommand(
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 9b184ae..9c916fa 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -15,9 +15,6 @@
  */
 package com.android.launcher3.ui.widget;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
 import static org.junit.Assert.assertNotNull;
 
 import android.platform.test.annotations.PlatinumTest;
@@ -33,7 +30,6 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.ui.TestViewHelpers;
 import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 import org.junit.Assume;
@@ -102,7 +98,6 @@
     /**
      * Test dragging a widget to the workspace and resize it.
      */
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/316910614
     @PlatinumTest(focusArea = "launcher")
     @Test
     public void testResizeWidget() throws Throwable {
diff --git a/tests/src/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..583652d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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
+
+import android.content.ContentResolver
+import android.net.Uri
+import android.os.Looper
+import java.io.InputStream
+import java.util.function.Supplier
+
+object RoboApiWrapper {
+
+    fun initialize() {}
+
+    fun registerInputStream(
+        contentResolver: ContentResolver,
+        uri: Uri,
+        inputStreamSupplier: Supplier<InputStream>
+    ) {}
+
+    fun waitForLooperSync(looper: Looper) {}
+}
diff --git a/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..9232268
--- /dev/null
+++ b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 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
+
+import android.content.ComponentName
+import android.content.ContentResolver
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.LauncherActivityInfo
+import android.content.pm.LauncherApps
+import android.net.Uri
+import android.os.Looper
+import android.os.Process
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.InputStream
+import java.util.function.Supplier
+import org.mockito.Mockito
+import org.mockito.kotlin.whenever
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.Shadows
+
+object RoboApiWrapper {
+
+    fun initialize() {
+        Shadows.shadowOf(
+                RuntimeEnvironment.getApplication().getSystemService(LauncherApps::class.java)
+            )
+            .addEnabledPackage(
+                Process.myUserHandle(),
+                InstrumentationRegistry.getInstrumentation().context.packageName
+            )
+        LauncherModelHelper.ACTIVITY_LIST.forEach {
+            installApp(ComponentName(InstrumentationRegistry.getInstrumentation().context, it))
+        }
+    }
+
+    private fun installApp(componentName: ComponentName) {
+        val app = RuntimeEnvironment.getApplication()
+        val user = Process.myUserHandle()
+
+        val pm = Shadows.shadowOf(app.packageManager)
+        val ai = pm.addActivityIfNotPresent(componentName)
+        pm.addIntentFilterForActivity(
+            componentName,
+            IntentFilter(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
+        )
+
+        val li = Mockito.mock(LauncherActivityInfo::class.java)
+        val appInfo = ApplicationInfo().apply { flags = 0 }
+        Mockito.doReturn(ai).whenever(li).activityInfo
+        Mockito.doReturn(appInfo).whenever(li).applicationInfo
+        Mockito.doReturn(user).whenever(li).user
+        Mockito.doReturn(1f).whenever(li).loadingProgress
+        Mockito.doReturn(componentName).whenever(li).componentName
+
+        Shadows.shadowOf(app.getSystemService(LauncherApps::class.java)).apply {
+            addActivity(user, li)
+            addEnabledPackage(user, componentName.packageName)
+            setActivityEnabled(user, componentName)
+            addApplicationInfo(user, componentName.packageName, ai.applicationInfo)
+        }
+    }
+
+    fun registerInputStream(
+        contentResolver: ContentResolver,
+        uri: Uri,
+        inputStreamSupplier: Supplier<InputStream>
+    ) {
+        Shadows.shadowOf(contentResolver).registerInputStreamSupplier(uri, inputStreamSupplier)
+    }
+
+    fun waitForLooperSync(looper: Looper) {
+        Shadows.shadowOf(looper).runToEndOfTasks()
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 7c6d684..02a862d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
 
+import android.graphics.Point;
 import android.util.Log;
 import android.widget.TextView;
 
@@ -129,6 +130,14 @@
     }
 
     /**
+     * @return the center coordinates of the icon
+     */
+    @NonNull
+    public Point getVisibleCenter() {
+        return getObject().getVisibleCenter();
+    }
+
+    /**
      * Create a regular expression pattern that matches strings containing all of the non-whitespace
      * characters of the app name, with any amount of whitespace added between characters (e.g.
      * newline for multiline app labels).
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index ac145b7..0edcfea 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -23,11 +23,9 @@
 import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
 import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
-import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH;
 import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 
 import android.graphics.Rect;
-import android.util.Log;
 import android.view.KeyEvent;
 
 import androidx.annotation.NonNull;
@@ -424,31 +422,32 @@
 
     protected boolean isActionsViewVisible() {
         if (!hasTasks() || isClearAllVisible()) {
-            Log.d(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
+            testLogD(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
             return false;
         }
         boolean isTablet = mLauncher.isTablet();
         if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
-            Log.d(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
+            testLogD(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
             return false;
         }
         OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
         if (task == null) {
-            Log.d(TAG, "Not expecting an actions bar: no current task");
+            testLogD(TAG, "Not expecting an actions bar: no current task");
             return false;
         }
         // In tablets, if focused task is not in center, overview actions aren't visible.
         if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
-            Log.d(TAG, "Not expecting an actions bar: device is tablet and task is not centered");
+            testLogD(TAG,
+                    "Not expecting an actions bar: device is tablet and task is not centered");
             return false;
         }
         if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
-            Log.d(TAG, "Not expecting an actions bar: device is phone and task is split");
+            testLogD(TAG, "Not expecting an actions bar: device is phone and task is split");
             // Overview actions aren't visible for split screen tasks, except for save app pair
             // button on tablets.
             return false;
         }
-        Log.d(TAG, "Expecting an actions bar");
+        testLogD(TAG, "Expecting an actions bar");
         return true;
     }
 
@@ -535,13 +534,9 @@
             return null;
         }
         Rect focusTaskSize = mLauncher.getOverviewTaskSize();
-        testLogD(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH, "focusTaskSize: " + focusTaskSize);
         int focusedTaskHeight = focusTaskSize.height();
         for (UiObject2 task : taskViews) {
             OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
-
-            testLogD(OVERVIEW_FOCUS_TASK_HEIGHT_MISMATCH,
-                    "overviewTask.getVisibleHeight(): " + overviewTask.getVisibleHeight());
             if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
                 return overviewTask;
             }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index ab48a21..5433fa7 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -284,8 +284,9 @@
      *
      * TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed.
      */
-    public boolean containsContentDescription(@Nullable String expected) {
-        String actual = mTask.getContentDescription();
+    public boolean containsContentDescription(@Nullable String expected,
+            OverviewSplitTask overviewSplitTask) {
+        String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription();
         if (actual == null && expected == null) {
             return true;
         }
@@ -295,6 +296,14 @@
         return actual.contains(expected);
     }
 
+    /**
+     * Returns whether the given String is contained in this Task's contentDescription. Also returns
+     * true if both Strings are null
+     */
+    public boolean containsContentDescription(@Nullable String expected) {
+        return containsContentDescription(expected, DEFAULT);
+    }
+
     private TaskViewType getType() {
         String resourceName = mTask.getResourceName();
         if (resourceName.endsWith("task_view_grouped")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index e6315f3..b4aaab7 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -52,7 +52,7 @@
 
         if (!mLauncher.isTransientTaskbar()) {
             Assert.assertEquals("Persistent taskbar should fill screen width",
-                    getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
+                    mLauncher.getRealDisplaySize().x, getVisibleBounds().width());
         }
     }