Merge "Move some Shell utils to the Shared package." into main
diff --git a/Android.bp b/Android.bp
index e358005..def024e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,24 @@
     ],
 }
 
+// Main Launcher source for compose, excluding the build config
+filegroup {
+    name: "launcher-compose-enabled-src",
+    srcs: [
+        "compose/facade/enabled/*.kt",
+        "compose/facade/core/*.kt",
+        "compose/features/**/*.kt",
+    ],
+}
+
+filegroup {
+    name: "launcher-compose-disabled-src",
+    srcs: [
+        "compose/facade/core/*.kt",
+        "compose/facade/disabled/*.kt",
+    ],
+}
+
 // Source code for quickstep build, on top of launcher-src
 filegroup {
     name: "launcher-quickstep-src",
@@ -51,6 +69,24 @@
     ],
 }
 
+// Source code for quickstep build with compose enabled, on top of launcher-src
+filegroup {
+    name: "launcher-quickstep-compose-enabled-src",
+    srcs: [
+        "quickstep/compose/facade/core/*.kt",
+        "quickstep/compose/facade/enabled/*.kt",
+        "quickstep/compose/features/**/*.kt",
+    ],
+}
+
+filegroup {
+    name: "launcher-quickstep-compose-disabled-src",
+    srcs: [
+        "quickstep/compose/facade/core/*.kt",
+        "quickstep/compose/facade/disabled/*.kt",
+    ],
+}
+
 // Alternate source when quickstep is not included
 filegroup {
     name: "launcher-src_no_quickstep",
@@ -74,6 +110,114 @@
     srcs: ["proguard.flags"],
 }
 
+// Opt-in configuration for Launcher3 code depending on Jetpack Compose.
+soong_config_module_type {
+    name: "launcher_compose_java_defaults",
+    module_type: "java_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: ["release_enable_compose_in_launcher"],
+    properties: [
+        "srcs",
+        "static_libs",
+    ],
+}
+
+// Opt-in configuration for Launcher Quickstep code depending on Jetpack Compose.
+soong_config_bool_variable {
+    name: "release_enable_compose_in_launcher",
+}
+
+soong_config_module_type {
+    name: "quickstep_compose_java_defaults",
+    module_type: "java_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: ["release_enable_compose_in_launcher"],
+    properties: [
+        "srcs",
+        "static_libs",
+    ],
+}
+
+soong_config_module_type {
+    name: "launcher_compose_tests_java_defaults",
+    module_type: "java_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: ["release_enable_compose_in_launcher"],
+    properties: [
+        "static_libs",
+    ],
+}
+
+launcher_compose_java_defaults {
+    name: "launcher_compose_defaults",
+    soong_config_variables: {
+        release_enable_compose_in_launcher: {
+            srcs: [
+                ":launcher-compose-enabled-src"
+            ],
+
+            // Compose dependencies
+            static_libs: [
+                "androidx.compose.runtime_runtime",
+                "androidx.compose.material3_material3",
+            ],
+
+            // By default, Compose is disabled and we compile the ComposeFacade
+            // in compose/launcher3/facade/disabled/.
+            conditions_default: {
+                srcs: [
+                    ":launcher-compose-disabled-src"
+                ],
+                static_libs: [],
+            },
+        },
+    },
+}
+
+quickstep_compose_java_defaults {
+    name: "quickstep_compose_defaults",
+    soong_config_variables: {
+        release_enable_compose_in_launcher: {
+            srcs: [
+                ":launcher-quickstep-compose-enabled-src"
+            ],
+
+            // Compose dependencies
+            static_libs: [
+                "androidx.compose.runtime_runtime",
+                "androidx.compose.material3_material3",
+            ],
+
+            // By default, Compose is disabled and we compile the ComposeFacade
+            // in compose/quickstep/facade/disabled/.
+            conditions_default: {
+                srcs: [
+                    ":launcher-quickstep-compose-disabled-src"
+                ],
+                static_libs: [],
+            },
+        },
+    },
+}
+
+launcher_compose_tests_java_defaults {
+    name: "launcher_compose_tests_defaults",
+    soong_config_variables: {
+        release_enable_compose_in_launcher: {
+            // Compose dependencies
+            static_libs: [
+                "androidx.compose.runtime_runtime",
+                "androidx.compose.ui_ui-test-junit4",
+                "androidx.compose.ui_ui-test-manifest",
+            ],
+
+            conditions_default: {
+                static_libs: [],
+            },
+        },
+    },
+}
+
 android_library {
     name: "launcher-aosp-tapl",
     libs: [
@@ -87,6 +231,7 @@
         "androidx.preference_preference",
         "SystemUISharedLib",
         "//frameworks/libs/systemui:animationlib",
+        "//frameworks/libs/systemui:contextualeducationlib",
         "launcher-testing-shared",
     ],
     srcs: [
@@ -147,6 +292,9 @@
 // Library with all the dependencies for building Launcher3
 android_library {
     name: "Launcher3ResLib",
+    defaults: [
+        "launcher_compose_defaults",
+    ],
     srcs: [],
     resource_dirs: ["res"],
     static_libs: [
@@ -164,6 +312,7 @@
         "//frameworks/libs/systemui:iconloader_base",
         "//frameworks/libs/systemui:view_capture",
         "//frameworks/libs/systemui:animationlib",
+        "//frameworks/libs/systemui:contextualeducationlib",
         "SystemUI-statsd",
         "launcher-testing-shared",
         "androidx.lifecycle_lifecycle-common-java8",
@@ -173,6 +322,7 @@
         "kotlinx_coroutines",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
+
     ],
     manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
@@ -250,6 +400,10 @@
 // Library with all the source code and dependencies for building Launcher Go
 android_library {
     name: "Launcher3GoLib",
+    defaults: [
+        "launcher_compose_defaults",
+        "quickstep_compose_defaults",
+    ],
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
@@ -281,6 +435,10 @@
 // Library with all the source code and dependencies for building Quickstep
 android_library {
     name: "Launcher3QuickStepLib",
+    defaults: [
+        "launcher_compose_defaults",
+        "quickstep_compose_defaults"
+    ],
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
@@ -308,7 +466,6 @@
 // Build rule for Quickstep app.
 android_app {
     name: "Launcher3QuickStep",
-
     static_libs: ["Launcher3QuickStepLib"],
     optimize: {
         proguard_flags_files: [":launcher-proguard-rules"],
@@ -349,7 +506,6 @@
 // eventually be merged into a single target
 android_app {
     name: "Launcher3Go",
-
     static_libs: ["Launcher3GoLib"],
     resource_dirs: [],
 
@@ -386,7 +542,6 @@
 }
 android_app {
     name: "Launcher3QuickStepGo",
-
     static_libs: ["Launcher3GoLib"],
     resource_dirs: [],
 
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index a779641..0df6c36 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -311,13 +311,6 @@
 }
 
 flag {
-    name: "enable_new_archiving_icon"
-    namespace: "launcher"
-    description: "Archived apps will use new icon in app title"
-    bug: "350758155"
-}
-
-flag {
     name: "enable_multi_instance_menu_taskbar"
     namespace: "launcher"
     description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
@@ -329,3 +322,13 @@
     description: "Settings screen supports navigating to child preference if the key is not on the screen"
     bug: "293390881"
 }
+
+flag {
+    name: "use_new_icon_for_archived_apps"
+    namespace: "launcher"
+    description: "Archived apps will use new cloud icon in app title instead of overlay"
+    bug: "350758155"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index f9327fe..11740ee 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -21,3 +21,13 @@
     description: "Enables rewritten version of TaskThumbnailViews in Overview"
     bug: "331753115"
 }
+
+flag {
+    name: "enable_hover_of_child_elements_in_taskview"
+    namespace: "launcher_overview"
+    description: "Enables child elements to receive hover events in TaskView and respond visually to those hover events."
+    bug: "342594235"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/compose/facade/core/BaseComposeFacade.kt b/compose/facade/core/BaseComposeFacade.kt
new file mode 100644
index 0000000..bc7ba47
--- /dev/null
+++ b/compose/facade/core/BaseComposeFacade.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.compose.core
+
+import android.content.Context
+import android.view.View
+
+interface BaseComposeFacade {
+    fun isComposeAvailable(): Boolean
+
+    fun initComposeView(appContext: Context): View
+}
diff --git a/compose/facade/disabled/ComposeFacade.kt b/compose/facade/disabled/ComposeFacade.kt
new file mode 100644
index 0000000..c1cbfff
--- /dev/null
+++ b/compose/facade/disabled/ComposeFacade.kt
@@ -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.compose
+
+import android.content.Context
+import android.view.View
+import com.android.launcher3.compose.core.BaseComposeFacade
+
+object ComposeFacade : BaseComposeFacade {
+    override fun isComposeAvailable(): Boolean = false
+
+    override fun initComposeView(appContext: Context): View {
+        error(
+            "Compose is not available. Make sure to check isComposeAvailable() before calling any" +
+                " other function on ComposeFacade."
+        )
+    }
+}
diff --git a/compose/facade/enabled/ComposeFacade.kt b/compose/facade/enabled/ComposeFacade.kt
new file mode 100644
index 0000000..d98a979f
--- /dev/null
+++ b/compose/facade/enabled/ComposeFacade.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.launcher3.compose
+
+import android.content.Context
+import android.view.View
+import androidx.compose.ui.platform.ComposeView
+import com.android.launcher3.compose.core.BaseComposeFacade
+
+object ComposeFacade : BaseComposeFacade {
+    override fun isComposeAvailable(): Boolean = true
+
+    override fun initComposeView(appContext: Context): View = ComposeView(appContext)
+}
diff --git a/go/quickstep/res/values-be/strings.xml b/go/quickstep/res/values-be/strings.xml
index 83374bb..de8766f 100644
--- a/go/quickstep/res/values-be/strings.xml
+++ b/go/quickstep/res/values-be/strings.xml
@@ -4,7 +4,7 @@
     <string name="app_share_drop_target_label" msgid="5804774105974539508">"Абагуліць праграму"</string>
     <string name="action_listen" msgid="2370304050784689486">"Праслухаць"</string>
     <string name="action_translate" msgid="8028378961867277746">"Перакласці"</string>
-    <string name="action_search" msgid="6269564710943755464">"Аб\'ектыў"</string>
+    <string name="action_search" msgid="6269564710943755464">"Аб’ектыў"</string>
     <string name="dialog_acknowledge" msgid="2804025517675853172">"ЗРАЗУМЕЛА"</string>
     <string name="dialog_cancel" msgid="6464336969134856366">"СКАСАВАЦЬ"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"НАЛАДЫ"</string>
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index f14cebd..1b9c661 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -52,6 +52,14 @@
         "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/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java"
+        "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java",
+    ],
+}
+
+filegroup {
+    name: "launcher3-quickstep-screenshot-tests-src",
+    path: "tests/multivalentScreenshotTests",
+    srcs: [
+        "tests/multivalentScreenshotTests/src/**/*.kt",
     ],
 }
diff --git a/quickstep/compose/facade/core/QuickstepComposeFeatures.kt b/quickstep/compose/facade/core/QuickstepComposeFeatures.kt
new file mode 100644
index 0000000..ca9e5c9
--- /dev/null
+++ b/quickstep/compose/facade/core/QuickstepComposeFeatures.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.compose.core
+
+interface QuickstepComposeFeatures
diff --git a/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt b/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt
new file mode 100644
index 0000000..0a4345a
--- /dev/null
+++ b/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.compose
+
+import android.content.Context
+import com.android.launcher3.compose.ComposeFacade
+import com.android.launcher3.compose.core.BaseComposeFacade
+import com.android.quickstep.compose.core.QuickstepComposeFeatures
+
+object QuickstepComposeFacade : BaseComposeFacade, QuickstepComposeFeatures {
+
+    override fun isComposeAvailable() = ComposeFacade.isComposeAvailable()
+
+    override fun initComposeView(appContext: Context) = ComposeFacade.initComposeView(appContext)
+}
diff --git a/quickstep/compose/facade/enabled/QuickstepComposeFacade.kt b/quickstep/compose/facade/enabled/QuickstepComposeFacade.kt
new file mode 100644
index 0000000..97cd300
--- /dev/null
+++ b/quickstep/compose/facade/enabled/QuickstepComposeFacade.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.compose
+
+import android.content.Context
+import com.android.launcher3.compose.ComposeFacade
+import com.android.launcher3.compose.core.BaseComposeFacade
+import com.android.quickstep.compose.core.QuickstepComposeFeatures
+
+object QuickstepComposeFacade : BaseComposeFacade, QuickstepComposeFeatures {
+    override fun isComposeAvailable() = ComposeFacade.isComposeAvailable()
+
+    override fun initComposeView(appContext: Context) = ComposeFacade.initComposeView(appContext)
+}
diff --git a/quickstep/res/drawable/bg_circle.xml b/quickstep/res/drawable/bg_circle.xml
deleted file mode 100644
index 506177b..0000000
--- a/quickstep/res/drawable/bg_circle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2020 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="#FFFFFFFF" />
-</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_desktop.xml b/quickstep/res/drawable/ic_desktop.xml
index 8de275d..11feca5 100644
--- a/quickstep/res/drawable/ic_desktop.xml
+++ b/quickstep/res/drawable/ic_desktop.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -15,17 +14,13 @@
   ~ limitations under the License.
   -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32.0dp"
-    android:height="32.0dp"
-    android:viewportWidth="32.0"
-    android:viewportHeight="32.0"
-    >
-    <group android:scaleX="0.5"
-        android:scaleY="0.5"
-        android:translateX="6.0"
-        android:translateY="6.0">
-        <path
-            android:fillColor="@android:color/black"
-            android:pathData="M5.958,37.708Q4.458,37.708 3.354,36.604Q2.25,35.5 2.25,34V18.292Q2.25,16.792 3.354,15.688Q4.458,14.583 5.958,14.583H9.5V5.958Q9.5,4.458 10.625,3.354Q11.75,2.25 13.208,2.25H34Q35.542,2.25 36.646,3.354Q37.75,4.458 37.75,5.958V21.667Q37.75,23.167 36.646,24.271Q35.542,25.375 34,25.375H30.5V34Q30.5,35.5 29.396,36.604Q28.292,37.708 26.792,37.708ZM5.958,34H26.792Q26.792,34 26.792,34Q26.792,34 26.792,34V21.542H5.958V34Q5.958,34 5.958,34Q5.958,34 5.958,34ZM30.5,21.667H34Q34,21.667 34,21.667Q34,21.667 34,21.667V9.208H13.208V14.583H26.833Q28.375,14.583 29.438,15.667Q30.5,16.75 30.5,18.25Z"/>
-    </group>
+    android:width="24dp"
+    android:height="24dp"
+    android:autoMirrored="true"
+    android:tint="?attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/black"
+        android:pathData="M240,640L600,640L600,440L240,440L240,640ZM660,520L720,520L720,320L360,320L360,380L660,380L660,520ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720Z" />
 </vector>
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 797ea45..a11974c 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -41,5 +41,6 @@
         android:textColor="?androidprv:attr/textColorOnAccent"
         android:layout_marginStart="@dimen/split_instructions_start_margin_cancel"
         android:text="@string/toast_split_select_app_cancel"
+        android:textStyle="bold"
         android:visibility="gone"/>
 </com.android.quickstep.views.SplitInstructionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index ac1a50a..34193d3 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/task"
+    android:id="@+id/task_view_single"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 64aa7e1..1564653 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -15,20 +14,19 @@
      limitations under the License.
 -->
 
-<com.android.quickstep.views.DesktopTaskView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+<com.android.quickstep.views.DesktopTaskView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/task"
+    android:id="@+id/task_view_desktop"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="true"
+    android:clipToPadding="true"
+    android:contentDescription="@string/recent_task_desktop"
     android:defaultFocusHighlightEnabled="false"
     android:focusable="true"
+    android:padding="0.1dp"
     launcher:focusBorderColor="?attr/materialColorOutline"
-    launcher:hoverBorderColor="?attr/materialColorPrimary"
-    android:clipToPadding="true"
-    android:padding="0.1dp">
+    launcher:hoverBorderColor="?attr/materialColorPrimary">
     <!-- Setting a padding of 0.1 dp since android:clipToPadding needs a non-zero value for
     padding to work-->
     <View
@@ -38,8 +36,8 @@
 
     <ViewStub
         android:id="@+id/icon"
-        android:inflatedId="@id/icon"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content" />
+        android:inflatedId="@id/icon" />
 
 </com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index da2b29f..cb4b98f 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -24,7 +24,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/task"
+    android:id="@+id/task_view_grouped"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index 736706a..e8f3d9d 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -35,6 +35,18 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 
+    <com.android.launcher3.taskbar.bubbles.BubbleBarView
+        android:id="@+id/taskbar_bubbles"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/bubblebar_size_with_pointer"
+        android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
+        android:paddingTop="@dimen/bubblebar_pointer_visible_size"
+        android:visibility="gone"
+        android:gravity="center"
+        android:layout_gravity="bottom"
+        android:clipChildren="false"
+        android:elevation="@dimen/bubblebar_elevation" />
+
     <com.android.launcher3.taskbar.navbutton.NearestTouchFrame
         android:id="@+id/navbuttons_view"
         android:layout_width="match_parent"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index f8c8977..c109328 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselleer"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kitsinstellings"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taakbalk word gewys"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taakbalk en borrels wys links"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taakbalk en borrels wys regs"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taakbalk is versteek"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taakbalk en borrels is versteek"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasiebalk"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Wys altyd Taakbalk"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Verander navigasiemodus"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index f5cef7b..f144118 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ይቅር"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ፈጣን ቅንብሮች"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"የተግባር አሞሌ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"የተግባር አሞሌ ይታያል"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"የተግባር አሞሌ እና አረፋዎች በግራ በኩል ይታያሉ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"የተግባር አሞሌ እና አረፋዎች በቀኝ በኩል ይታያሉ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"የተግባር አሞሌ ተደብቋል"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"የተግባር አሞሌ እና አረፋዎች ተደብቀዋል"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"የአሰሳ አሞሌ"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ሁልጊዜ የተግባር አሞሌ ያሳዩ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"የአሰሳ ሁነታን ይለውጡ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 52a18e9..629580f 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"إلغاء"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"إعدادات سريعة"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"شريط التطبيقات"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"تم إظهار شريط التطبيقات"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"يتم عرض \"شريط التطبيقات\" و\"فقاعات المحادثات\" يمينًا"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"يتم عرض \"شريط التطبيقات\" و\"فقاعات المحادثات\" يسارًا"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"تم إخفاء شريط التطبيقات"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"تم إخفاء \"شريط التطبيقات\" و\"فقاعات المحادثات\""</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"شريط التنقل"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"إظهار شريط التطبيقات دائمًا"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"تغيير وضع التنقل"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index d811543..252697c 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল কৰক"</b></string>
+    <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>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 3108ffe..7d7ed56 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ləğv edin"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Sürətli Ayarlar"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tapşırıq paneli"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"İşləmə paneli göstərilir"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"İşləmə paneli, yumrucuqlar solda göstərilir"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"İşləmə paneli, yumrucuqlar sağda göstərilir"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"İşləmə paneli gizlədilib"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"İşləmə paneli, yumrucuqlar gizlədilib"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naviqasiya paneli"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"İşləmə paneli həmişə görünsün"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Naviqasiya rejimini dəyişin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index e6074b0..d8f608d 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brza podešavanja"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka zadataka je prikazana"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Prikaz zadataka/oblačića levo"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Prikaz zadataka/oblačića desno"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka zadataka je skrivena"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Skriveni zadaci/oblačići"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Uvek prikazuj traku zadataka"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Promeni režim navigacije"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 5b871d4..b403e7f 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -39,7 +39,7 @@
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Атрымліваць прапановы праграм"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Не, дзякуй"</string>
     <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Налады"</string>
-    <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Тут з\'яўляюцца праграмы, якімі вы карыстаецеся найбольш часта. Гэты спіс змяняецца на падставе вашых дзеянняў"</string>
+    <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Тут з’яўляюцца праграмы, якімі вы карыстаецеся найбольш часта. Гэты спіс змяняецца на падставе вашых дзеянняў"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Перацягніце праграмы з ніжняга радка, каб атрымліваць прапановы праграм"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Прапановы праграм дададзены на свабоднае месца"</string>
     <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Прапановы праграм уключаны"</string>
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасаваць"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Хуткія налады"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панэль задач"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панэль задач паказана"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Панэль задач і ўсплывальныя чаты паказваюцца злева"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Панэль задач і ўсплывальныя чаты паказваюцца справа"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панэль задач схавана"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Панэль задач і ўсплывальныя чаты схаваны"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панэль навігацыі"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Заўсёды паказваць панэль задач"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Змяніць рэжым навігацыі"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index dd87de8..6fb6127 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отказ"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Бързи настройки"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента на задачите"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Лентата на задачите се показва"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Лентата и балончетата са вляво"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Лентата и балончетата са вдясно"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Лентата на задачите е скрита"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Лентата и балончетата са скрити"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигация"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Лентата на задачите винаги да се показва"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Промяна на режима на навигация"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 99a815f..043c0d6 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল করুন"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"দ্রুত সেটিংস"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"টাস্কবার"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"\'টাস্কবার\' দেখানো হয়েছে"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"টাস্কবার ও বাবল বাঁদিকে দেখানো হয়েছে"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"টাস্কবার ও বাবল ডানদিকে দেখানো হয়েছে"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"\'টাস্কবার\' লুকানো রয়েছে"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"টাস্কবার ও বাবল লুকানো হয়েছে"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশন বার"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"সবসময় টাস্কবার দেখুন"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"\'নেভিগেশন\' মোড পরিবর্তন করুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 5f445ab..af7fe61 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -92,14 +92,14 @@
     <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napoč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 navigiranja sistemom"</annotation></string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sistemom"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
     <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="1532690483356445639"><b>"Otkaži"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Odustani"</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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka zadataka je prikazana"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Traka zadataka/oblačići prik. lijevo"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Traka zadataka/oblačići prik. desno"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka zadataka je sakrivena"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Traka zadataka/oblačići sakriveni"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigaciona traka"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 2b8fadf..cc3112a 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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">"Ordinador"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel·la"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. ràpida"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tasques"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Es mostra la Barra de tasques"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra i bombolles a l\'esquerra"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra i bombolles a la dreta"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"S\'ha amagat la Barra de tasques"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra i bombolles amagades"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegació"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tasques sempre visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Canvia el mode de navegació"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6e432de..546aa1e 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušit"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rychlé nastavení"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikací"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Panel aplikací je zobrazen"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel a bubliny vlevo zobr."</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel a bubliny vpravo zobr."</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Panel aplikací je skrytý"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel a bubliny jsou skryty"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigační panel"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Vždy zobrazovat panel aplikací"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Změnit režim navigace"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index c73f49c..ae10343 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuller"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kvikmenu"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Proceslinje"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Proceslinjen vises"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Proceslinje og bobler til venstre"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Proceslinje og bobler til højre"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Proceslinjen er skjult"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Proceslinje og bobler skjult"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationslinje"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Vis altid proceslinjen"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Skift navigationstilstand"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 8f571ce..03b5bb9 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Abbrechen"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Schnelleinstellungen"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskleiste"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskleiste eingeblendet"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskleiste &amp; Bubbles links eingeblendet"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskleiste &amp; Bubbles rechts eingeblendet"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskleiste ausgeblendet"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskleiste &amp; Bubbles ausgeblendet"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationsleiste"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Taskleiste immer anzeigen"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigationsmodus ändern"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 011c800..a717678 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -67,7 +67,7 @@
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Σύρετε για μετάβαση στην αρχική οθόνη"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Σύρετε προς τα πάνω από το κάτω μέρος της οθόνης. Αυτή η κίνηση σάς μεταφέρει πάντα στην αρχ. οθόνη."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Σύρετε από το κάτω άκρο προς τα πάνω με 2 δάχτ. Αυτή η κίνηση σάς μεταφέρει πάντα στην αρχική οθόνη."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Αρχική"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Μετάβαση στην αρχική οθόνη"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Σύρετε προς τα επάνω από το κάτω μέρος της οθόνης"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Μπράβο!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Φροντίστε να σύρετε προς τα επάνω από το κάτω άκρο της οθόνης"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ακύρωση"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Γρήγορες ρυθμ."</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Γραμμή εργαλείων"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Η γραμμή εργαλείων εμφανίζεται"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Εμφάν. αριστ. γρ. εργ. και συν."</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Εμφάν. δεξιάς γρ. εργ. και συν."</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Η γραμμή εργαλείων είναι κρυφή"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Απόκρυψη εργαλείων και συννεφ."</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Γραμμή πλοήγησης"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Εμφάνιση Γραμμής εργαλείων"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Αλλαγή τρόπου πλοήγησης"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 2183919..e069b8f 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+    <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 organization"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index ba55585..777db28 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Cancel‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <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 organization‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 7df97ef..3d78c71 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápida"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra tareas y burb. a la izq."</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra tareas y burb. a la der."</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra tareas y burb. ocultas"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 353ff4c..f878954 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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">"Ordenador"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</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>
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar apps emparejadas"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra aplicación para usar la pantalla dividida"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida."</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+    <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">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ajustes rápidos"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Tareas y burbujas a izquierda"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Tareas y burbujas a derecha"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Tareas y burbujas ocultas"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 6b78c1f..4468533 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -72,7 +72,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Väga hea!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pühkige kindlasti ekraani alumisest servast üles."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Hoidke sõrme aknal pisut kauem, enne kui vabastate"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge."</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage Seaded."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Tegite rakenduste vahel vahetamise liigutuse"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Pühkige rakenduste vahetamiseks"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kiirseaded"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tegumiriba"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Tegumiriba on kuvatud"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Tegumiriba ja mullid kuvatakse"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Tegumiriba ja mullid kuvatakse paremal"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Tegumiriba on peidetud"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Tegumiriba ja mullid on peidetud"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeerimisriba"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Kuva tegumiriba alati"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigeerimisrežiimi muutmine"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 058ade5..fe138b8 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Utzi"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ezarpen bizkorrak"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Zereginen barra"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Zereginen barra ikusgai dago"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Zereginen barra eta burbuilak ezkerrean ikusgai"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Zereginen barra eta burbuilak eskuinean ikusgai"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Zereginen barra itxita dago"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Zereginen barra eta burbuilak ezkutatuta"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Nabigazio-barra"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Erakutsi beti zereginen barra"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Aldatu nabigazio modua"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index f6f51b7..cb88eba 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"حالت رایانه"</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,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"لغو کردن"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"تنظیمات فوری"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"نوار وظیفه"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"نوار وظیفه نمایان است"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"نمایش نوار وظیفه و حبابک‌ها در چپ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"نمایش نوار وظیفه و حبابک‌ها در راست"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"نوار وظیفه پنهان است"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"نوار وظیفه و حبابک‌ها پنهان هستند"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نوار پیمایش"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"نوار وظیفه همیشه نشان داده شود"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"تغییر حالت پیمایش"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 91f64ed..4d610f2 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Peruuta"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Pika-asetukset"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tehtäväpalkki"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Tehtäväpalkki näkyvissä"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Vas. palkki ja kuplat näkyvissä"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Oik. palkki ja kuplat näkyvissä"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Tehtäväpalkki piilotettu"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Palkki ja kuplat piilotettu"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigointipalkki"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Näytä tehtäväpalkki aina"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Vaihda navigointitilaa"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index e567239..179be5f 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Enr. paire d\'applis"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre appli pour utiliser l\'Écran divisé"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuler"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection d\'écran divisé"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre appli pour utiliser l\'écran partagé"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'appli ou votre organisation n\'autorise pas cette action"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Paramètres rapides"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barre des tâches/bulles à gauche"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barre des tâches/bulles à droite"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barre des tâches/bulles masquées"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Tjrs afficher barre des tâches"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Changer de mode de navigation"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ddab232..8568c40 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -88,7 +88,7 @@
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bravo !"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriel <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Tout est prêt !"</string>
-    <string name="allset_hint" msgid="459504134589971527">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Balayez vers le haut pour revenir à l\'accueil"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Appuyez sur le bouton d\'accueil pour accéder à votre écran d\'accueil"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Vous pouvez maintenant utiliser votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"appareil"</string>
@@ -99,7 +99,8 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer la 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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Réglages rapides"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barre des tâches et bulles affichées à gauche"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barre des tâches et bulles affichées à droite"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barre des tâches et bulles masquées"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Barre des tâches tjs visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Modifier le mode de navigation"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 053a48f..e6400ca 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -90,7 +90,7 @@
     <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">"Xa podes comezar a utilizar o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</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_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración da navegación do sistema"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Configuración rápida"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Estase mostrando a barra de tarefas"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra e burbullas á esquerda"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra e burbullas á dereita"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Non se está mostrando a barra de tarefas"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra e burbullas ocultas"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre a barra de tarefas"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar modo de navegación"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index a081ab5..2adf594 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"રદ કરો"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ઝડપી સેટિંગ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ટાસ્કબાર"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ટાસ્કબાર બતાવવામાં આવ્યો"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ટાસ્કબાર અને બબલ ડાબે બતાવ્યા"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ટાસ્કબાર અને બબલ જમણે બતાવ્યા"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ટાસ્કબાર છુપાવવામાં આવ્યો"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ટાસ્કબાર અને બબલ છુપાવેલા છે"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"નૅવિગેશન બાર"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"હંમેશાં ટાસ્કબાર બતાવો"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"નૅવિગેશન મોડ બદલો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 1e74c4a..56d2b39 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -92,14 +92,14 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"अभी नहीं"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"फटाफट सेटिंग"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार दिखाया गया"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार और बबल बाईं ओर हैं"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार और बबल दाईं ओर हैं"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार छिपाया गया"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार और बबल छिपाए गए"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेविगेशन बार"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार हमेशा दिखाएं"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"नेविगेशन का मोड बदलें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index fc85be9..97f4ee0 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Spremi par apl."</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Odustani"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Odustani"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zatvori odabir podijeljenog zaslona"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka sa zadacima"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka sa zadacima prikazana"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Traka sa zadacima/oblačići prikazani lijevo"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Traka sa zadacima/oblačići prikazani desno"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka sa zadacima skrivena"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Traka sa zadacima/oblačići skriveni"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigacijska traka"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 3a539d4..2d0bd18 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Mégse"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Gyorsbeállítások"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tálca"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Feladatsáv megjelenítve"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Feladatsáv és buborék balra"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Feladatsáv és buborék jobbra"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Feladatsáv elrejtve"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Rejtett feladatsáv és buborék"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigációs sáv"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Mindig megjelenő Feladatsáv"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigációs mód módosítása"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index d8503f3..947e34e 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Չեղարկել"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Արագ կարգավորումներ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Խնդրագոտի"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Խնդրագոտին ցուցադրվում է"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Հավելվածների վահանակն ու ամպիկները տեսանելի են ձախ կողմում"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Հավելվածների վահանակն ու ամպիկները տեսանելի են աջ կողմում"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Խնդրագոտին թաքցված է"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Հավելվածների վահանակն ու ամպիկները թաքցված են"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Նավիգացիայի գոտի"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Միշտ ցույց տալ վահանակը"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Փոխել նավիգացիայի ռեժիմը"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d4def8d..16334ca 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -79,7 +79,7 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Untuk beralih dari satu aplikasi ke aplikasi lain, geser ke atas dari bagian bawah layar, tahan, lalu lepaskan."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Untuk beralih antar-aplikasi, geser ke atas dengan 2 jari dari bawah layar, tahan, lalu lepaskan."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Beralih aplikasi"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Geser ke atas dari bagian bawah layar, tahan, kemudian lepaskan"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Geser ke atas dari bagian bawah layar, tahan, kemudian lepas"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Bagus."</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Semua siap"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Selesai"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setelan Cepat"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar ditampilkan"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar &amp; balon kiri ditampilkan"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar &amp; bubbles kanan ditampilkan"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar disembunyikan"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar &amp; balon disembunyikan"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Menu navigasi"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Selalu tampilkan Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Ubah mode navigasi"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index f2dd60c..ed1cf85 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Hætta við"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Flýtistillingar"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Verkstika"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Forritastika sýnd"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Verkstika og blöðrur sýndar til vinstri"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Verkstika og blöðrur sýndar til hægri"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Forritastika falin"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Verkstika og blöðrur eru faldar"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Yfirlitsstika"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Alltaf sýna forritastiku"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Breyta leiðsagnarstillingu"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 9ed28c1..29a84dd 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annulla"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index da8b37d..e30f7df 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -88,7 +88,7 @@
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"יפה!"</string>
     <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_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="default_device_name" msgid="6660656727127422487">"מכשיר"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ביטול"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"הגדרות מהירות"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"סרגל האפליקציות"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"סרגל האפליקציות מוצג"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"סרגל האפליקציות והבועות מוצגים משמאל"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"סרגל האפליקציות והבועות מוצגים מימין"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"סרגל האפליקציות מוסתר"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"סרגל האפליקציות והבועות הוסתרו"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"סרגל הניווט"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"סרגל האפליקציות מוצג תמיד"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"שינוי מצב הניווט"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 54f51da..bb6d07b 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"デスクトップ"</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,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"キャンセル"</b></string>
+    <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>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5328012..0ffc3e8 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"გაუქმება"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"სწრაფი პარამეტრები"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ამოცანათა ზოლი"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ამოცანათა ზოლი ნაჩვენებია"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ამოცანათა ზოლი და ბუშტები ჩანს მარცხნივ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ამოცანათა ზოლი და ბუშტები ჩანს მარჯვნივ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ამოცანათა ზოლი დამალულია"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ამოცანათა ზოლი და ბუშტები დამალულია"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ნავიგაციის ზოლი"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ამოცანათა ზოლის მუდამ ჩვენება"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"შეცვალეთ ნავიგაციის რეჟიმი"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 54c1795..8bf7111 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Бас тарту"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Жылдам параметрлер"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапсырмалар жолағы"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапсырмалар жолағы көрсетілді"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Тапсырмалар жолағы мен қалқыма терезелер сол жақта көрсетілген"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Тапсырмалар жолағы мен қалқыма терезелер оң жақта көрсетілген"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапсырмалар жолағы жасырылды"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Тапсырмалар жолағы мен қалқыма терезелер жасырылған"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигация жолағы"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Тапсырма жолағын үнемі көрсету"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Навигация режимін өзгерту"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 698f33c..06cd015 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"ដែសថប"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"បោះបង់"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ការកំណត់រហ័ស"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"របារកិច្ចការ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"បានបង្ហាញរបារកិច្ចការ"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"បានបង្ហាញរបារកិច្ចការ និងផ្ទាំងអណ្ដែតនៅខាងឆ្វេង"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"បានបង្ហាញរបារកិច្ចការ និងផ្ទាំងអណ្ដែតនៅខាងស្ដាំ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"បានលាក់របារកិច្ចការ"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"បានលាក់របារកិច្ចការ និងផ្ទាំងអណ្ដែត"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"របាររុករក"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ប្ដូរ​មុខងាររុករក"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 6a86e38..26f1d6f 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ರದ್ದುಮಾಡಿ"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ಟಾಸ್ಕ್‌ಬಾರ್"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ಟಾಸ್ಕ್‌ಬಾರ್ ತೋರಿಸಲಾಗಿದೆ"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ಟಾಸ್ಕ್‌ಬಾರ್ &amp; ಬಬಲ್ಸ್ ತೋರಿಸಲಾಗಿದೆ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ಟಾಸ್ಕ್‌ಬಾರ್ &amp; ಬಬಲ್ಸ್ ಬಲಭಾಗದಲ್ಲಿ ತೋರಿಸಲಾಗಿದೆ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ಟಾಸ್ಕ್‌ಬಾರ್ ಮರೆಮಾಡಲಾಗಿದೆ"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ಟಾಸ್ಕ್‌ಬಾರ್ &amp; ಬಬಲ್ಸ್ ಮರೆಮಾಡಲಾಗಿದೆ"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್‌ಬಾರ್ ತೋರಿಸಿ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ನ್ಯಾವಿಗೇಶನ್ ಮೋಡ್ ಬದಲಾಯಿಸಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 31942fb..04fd457 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -90,7 +90,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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"취소"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"빠른 설정"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"태스크 바"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"태스크 바 표시"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"태스크 바와 대화창을 왼쪽에 표시"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"태스크 바와 대화창을 오른쪽에 표시"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"태스크 바 숨김"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"태스크 바 및 대화창 숨김"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"탐색 메뉴"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"태스크 바 항상 표시"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"탐색 모드 변경"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8805bd0..f0156de 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -90,7 +90,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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Жокко чыгаруу"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ыкчам параметрлер"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапшырмалар тактасы"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапшырмалар панели көрсөтүлдү"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Тапшырмалар панели, калкыма билдирмелер сол жакта көрсөтүлдү"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Тапшырмалар панели, калкыма билдирмелер оң жакта көрсөтүлгөн"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапшырмалар панели жашырылды"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Тапшырмалар панели жана калкып чыкма билдирмелер жашырылган"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Чабыттоо тилкеси"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Такта ар дайым көрүнсүн"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Өтүү режимин өзгөртүү"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 9e70a5c..81a52b1 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ຍົກເລີກ"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ການຕັ້ງຄ່າດ່ວນ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ແຖບໜ້າວຽກ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ແຖບໜ້າວຽກທີ່ສະແດງຢູ່"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ແຖບໜ້າວຽກ ແລະ ຟອງສະແດງຢູ່ເບື້ອງຊ້າຍ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ແຖບໜ້າວຽກ ແລະ ຟອງສະແດງຢູ່ເບື້ອງຂວາ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ແຖບໜ້າວຽກທີ່ເຊື່ອງໄວ້ຢູ່"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ແຖບໜ້າວຽກ ແລະ ຟອງຖືກເຊື່ອງໄວ້"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ແຖບການນຳທາງ"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ປ່ຽນໂໝດການນຳທາງ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index f78fa30..ec45620 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atšaukti"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Spartieji nustatymai"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Užduočių juosta"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Užduočių juosta rodoma"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Užduočių juosta ir burbulai rodomi kairėje"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Užduočių juosta ir burbulai rodomi dešinėje"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Užduočių juosta paslėpta"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Užduočių juosta ir burbulai paslėpti"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naršymo juosta"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Visada rodyti užduočių juostą"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Keisti naršymo režimą"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 799e8d1..4474e7c 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atcelt"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ātrie iestatīj."</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Uzdevumu josla"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Uzdevumu josla tiek rādīta"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Uzdevumu josla/burbuļi pa kreisi"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Uzdevumu josla/burbuļi pa labi"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Uzdevumu josla paslēpta"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Uzdevumu josla/burbuļi paslēpti"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigācijas josla"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Vienmēr rādīt uzdevumu joslu"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Mainīt navigācijas režīmu"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 04f35ba..f503e59 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"Работна површина"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брзи поставки"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента со задачи"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Лентата со задачи е прикажана"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Лен. со зад. и бал. се лево"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Лен. со зад. и бал. се десно"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Лентата со задачи е скриена"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Лен. со зад. и бал. се скриени"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигација"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Секогаш прикажувај „Лента“"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Променете режим на навигација"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 0db3e1f..5448f60 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"റദ്ദാക്കുക"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ദ്രുത ക്രമീകരണം"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ടാസ്‌ക്ബാർ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ടാസ്‌ക്ബാർ കാണിച്ചിരിക്കുന്നു"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ടാസ്ക്ബാറും ബബിളും ഇടതുവശത്ത്"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ടാസ്ക്ബാറും ബബിളും വലതുവശത്ത്"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ടാസ്‌ക്ബാർ മറച്ചിരിക്കുന്നു"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ടാസ്ക്ബാറും ബബിളും മറച്ചു"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"നാവിഗേഷൻ ബാർ"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ടാസ്‌ക്ബാർ എപ്പോഴും കാണിക്കൂ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"നാവിഗേഷൻ മോഡ് മാറ്റുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index a76117a..18c66d7 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Цуцлах"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Шуурхай тохиргоо"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Ажлын хэсэг"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ажлын хэсгийг харуулсан"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Ажлын хэсэг, бөмбөлгийг зүүн талд харуулсан"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Ажлын хэсэг, бөмбөлгийг баруун талд харуулсан"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Ажлын хэсгийг нуусан"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Ажлын хэсэг, бөмбөлгийг нуусан"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигацын самбар"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Ажлын хэсгийг үргэлж харуулах"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Навигацын горимыг өөрчлөх"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 09f40ab..45f768a 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द करा"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"क्विक सेटिंग्ज"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार दाखवलेला आहे"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार आणि डावे बबल दाखवले"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार आणि उजवे बबल लपवले"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार लपवलेले आहे"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार आणि बबल लपवले आहेत"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेव्हिगेशन बार"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"नेहमी टास्कबार दाखवा"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"नेव्हिगेशन मोड बदला"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 72887ef..5d56cd1 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Simpan gandingan apl"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketik apl lain untuk menggunakan skrin pisah"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih apl lain untuk menggunakan skrin pisah"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Batal"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar daripada pilihan skrin pisah"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih apl lain untuk menggunakan skrin pisah"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 749c1b5..06740db 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"မလုပ်တော့"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"အမြန်ဆက်တင်များ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"လုပ်ဆောင်စရာဘား"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar ပြထားသည်"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ဘယ်ဘက်၌ Taskbar နှင့် ပူဖောင်းကွက် ပြထားသည်"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ညာဘက်၌ Taskbar နှင့် ပူဖောင်းကွက် ပြထားသည်"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar ဖျောက်ထားသည်"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar နှင့် ပူဖောင်းကွက် ဖျောက်ထားသည်"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"လမ်းညွှန်ဘား"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Taskbar အမြဲပြရန်"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ရွှေ့ကြည့်သည့်မုဒ် ပြောင်းရန်"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 245945b..6a31efa 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hurtiginnst."</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Oppgavelinje"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Oppgavelinjen vises"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Venstre oppgavelinje/boble vises"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Høyre oppgavelinje/bobler vises"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Oppgavelinjen er skjult"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Oppgavelinje og bobler skjult"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasjonsrad"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Vis alltid oppgavelinjen"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Endre navigasjonsmodus"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index f881637..b4a0136 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द गर्नुहोस्"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"द्रुत सेटिङ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार देखाइएको छ"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार र बबल बार बायाँतिर देखाइएका छन्"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार र बबल बार दायाँतिर देखाइएका छन्"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार लुकाइएको छ"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार र बबल बार लुकाइएका छन्"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेभिगेसन बार"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार सधैँ देखाउनुहोस्"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"नेभिगेसन मोड बदल्नुहोस्"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 09f8aca..0cd8141 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"App-paar opslaan"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op nog een app om je scherm te splitsen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies een andere app om gesplitst scherm te gebruiken"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuleren"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuleren"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sluit de selectie voor gesplitst scherm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies andere app om gesplitst scherm te gebruiken"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snelle instellingen"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taakbalk wordt getoond"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taakbalk en bubbels links getoond"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taakbalk en bubbels rechts getoond"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taakbalk is verborgen"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taakbalk en bubbels verborgen"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatiebalk"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Taakbalk altijd tonen"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigatiemodus wijzigen"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 83522f3..97b0493 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ବାତିଲ କରନ୍ତୁ"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କୁଇକ ସେଟିଂସ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ଟାସ୍କବାର ଦେଖାଯାଇଛି"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ଟାସ୍କବାର ଓ ବବଲ ବାମରେ ଦେଖାଯାଇଛି"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ଟାସ୍କବାର ଓ ବବଲ ଡାହାଣରେ ଦେଖାଯାଇଛି"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ଟାସ୍କବାର ଓ ବବଲ ଲୁଚାଯାଇଛି"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ନାଭିଗେସନ ବାର"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ନାଭିଗେସନ ମୋଡ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 197fc6c..bd7e4d8 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ਰੱਦ ਕਰੋ"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ਟਾਸਕਬਾਰ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ਟਾਸਕਬਾਰ ਨੂੰ ਦਿਖਾਇਆ ਗਿਆ"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ਟਾਸਕਬਾਰ ਤੇ ਬਬਲ ਨੂੰ ਖੱਬੇ ਦਿਖਾਇਆ"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ਟਾਸਕਬਾਰ ਤੇ ਬਬਲ ਨੂੰ ਸੱਜੇ ਦਿਖਾਇਆ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ਟਾਸਕਬਾਰ ਨੂੰ ਲੁਕਾਇਆ ਗਿਆ"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ਟਾਸਕਬਾਰ ਅਤੇ ਬਬਲ ਨੂੰ ਲੁਕਾਇਆ ਗਿਆ"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਓ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ਨੈਵੀਗੇਸ਼ਨ ਮੋਡ ਬਦਲੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 5d6d927..942cdde 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Zapisz parę"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Aby podzielić ekran, kliknij drugą aplikację"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Aby podzielić ekran, wybierz drugą aplikację"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anuluj"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anuluj"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Wyjdź z wyboru podzielonego ekranu"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Wybierz drugą aplikację, aby podzielić ekran"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Szybkie ustawienia"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Pasek aplikacji"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Pasek aplikacji widoczny"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Pasek i dymki po lewej"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Pasek i dymki po prawej"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Pasek aplikacji ukryty"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Pasek i dymki są ukryte"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Pasek nawigacyjny"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Zawsze pokazuj pasek aplikacji"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Zmień tryb nawigacji"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 4787ec3..50058c9 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar par de apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outra app para usar o ecrã dividido"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saia da seleção de ecrã dividido"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolher outra app para usar o ecrã dividido"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Definiç. rápidas"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tarefas apresentada"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra de tarefas/balões à esq."</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra de tarefas/balões à dir."</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tarefas ocultada"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra tarefas/balões ocultos"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre Barra de tarefas"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Alterar modo de navegação"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index cb45f07..6ad7b2e 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"Modo área de trabalho"</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>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápidas"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tarefas visível"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra de tar. e balões à esq."</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra de tar. e balões à dir."</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tarefas oculta"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra de tar. e balões ocultos"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Sempre mostrar a Barra de tarefas"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Mudar o modo de navegação"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 31b1951..9b264b8 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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">"Computer"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulează"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setări rapide"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Bară de activități"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Bara de activități este afișată"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Bară și baloane stânga afișate"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Bară &amp; baloane dreapta afișate"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Bara de activități este ascunsă"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Bară și baloane ascunse"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bară de navigare"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Afișează mereu bara"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Schimbă modul de navigare"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 72559f6..5bcae00 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"Мультиоконный режим"</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 +72,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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Быстрые настройки"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель задач"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панель задач показана"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Слева панель задач, подсказки"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Справа панель задач, подсказки"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панель задач скрыта"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Скрыты панель задач, подсказки"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навигации"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Всегда показывать панель задач"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Изменить режим навигации"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 6e7aabb..b23617f 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"අවලංගු කරන්න"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ඉක්මන් සැකසීම්"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"කාර්ය තීරුව"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"කාර්ය තීරුව පෙන්වා ඇත"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"කාර්ය තීරුව සහ බුබුළු පෙන්වා ඇත"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"කාර්ය තීරුව සහ බුබුළු දකුණට පෙන්වා ඇත"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"කාර්ය තීරුව සඟවා ඇත"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"කාර්ය තීරුව සහ බුබුළු සඟවා ඇත"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"සංචලන තීරුව"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"සංචාලන ප්‍රකාරය වෙනස් කරන්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 5fbe4f1..278ad0e 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -90,7 +90,7 @@
     <string name="allset_title" msgid="5021126669778966707">"Hotovo"</string>
     <string name="allset_hint" msgid="459504134589971527">"Potiahnutím nahor prejdete na plochu"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Na plochu prejdete klepnutím na tlačidlo plochy"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> môžete začať používať"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"Môžete <xliff:g id="DEVICE">%1$s</xliff:g> začať používať"</string>
     <string name="default_device_name" msgid="6660656727127422487">"zariadenie"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavenia navigácie systémom"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušiť"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rýchle nastavenia"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikácií"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Panel aplikácií je zobrazený"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel aplik. a bubl. sú vľavo"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel aplik. a bubl. sú vpravo"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Panel aplikácií je skrytý"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel aplik. a bubl. sú skryté"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigačný panel"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Zobrazovať panel aplikácií"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Zmeniť režim navigácie"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 62c0c3c..0c201b4 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Shrani par aplikacij"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Za razdeljeni zaslon se dotaknite še 1 aplikacije"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Prekliči"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Prekliči"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zapri izbiro razdeljenega zaslona"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hitre nastavitve"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Opravilna vrstica"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Opravilna vrstica je prikazana"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Prikazani so opravilna vrstica in oblački na levi"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Prikazani so opravilna vrstica in oblački na desni"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Opravilna vrstica je skrita"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Opravilna vrstica in oblački so skriti"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Vrstica za krmarjenje"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Stalen prikaz oprav. vrstice"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Spreminjanje načina navigacije"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 78f2733..cd5725d 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulo"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cilësimet shpejt"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Shiriti i detyrave"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Shiriti i detyrave i shfaqur"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Shiriti i detyrave dhe flluskat majtas janë shfaqur"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Shiriti i detyrave dhe flluskat djathtas janë shfaqur"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Shiriti i detyrave i fshehur"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Shiriti i detyrave dhe flluskat janë fshehur"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Shiriti i navigimit"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Shfaq gjithmonë shiritin e detyrave"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Ndrysho modalitetin e navigimit"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index ee3a467..708406b 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брза подешавања"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Трака задатака"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Трака задатака је приказана"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Приказ задатака/облачића лево"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Приказ задатака/облачића десно"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Трака задатака је скривена"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Скривени задаци/облачићи"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Увек приказуј траку задатака"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Промени режим навигације"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index e2cf71f..ef0ef76 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snabbinställn."</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Aktivitetsfält"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Aktivitetsfältet visas"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Vänster fält och bubblor visas"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Höger fält och bubblor visas"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Aktivitetsfältet är dolt"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Fält och bubblor dolda"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeringsfält"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Visa alltid aktivitetsfältet"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Ändra navigeringsläge"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 66feb58..63b5922 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ghairi"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Mipangilio ya Haraka"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Upauzana"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Upauzana umeonyeshwa"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Upauzana na viputo vinaonyeshwa kushoto"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Upauzana na viputo vinaonyeshwa kulia"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Upauzana umefichwa"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Upauzana na viputo vimefichwa"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Sehemu ya viungo muhimu"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Onyesha Zana kila wakati"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Badilisha hali ya usogezaji"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 43e12ee..5159245 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -90,7 +90,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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ரத்துசெய்"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"விரைவு அமைப்புகள்"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"செயல் பட்டி"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"செயல் பட்டி காட்டப்படுகிறது"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"செயல் பட்டி &amp; குமிழை இடதுபுறம் காட்டும்"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"செயல் பட்டி &amp; குமிழை வலதுபுறம் காட்டும்"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"செயல் பட்டி மறைக்கப்பட்டுள்ளது"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"செயல் பட்டி &amp; குமிழை மறைக்கும்"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"வழிசெலுத்தல் பட்டி"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"செயல் பட்டியை எப்போதும் காட்டு"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"வழிசெலுத்தல் பயன்முறையை மாற்று"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index fbe67dc..8c8e688 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"రద్దు చేయండి"</b></string>
+    <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>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 7816628..2c5f9a6 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ยกเลิก"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"การตั้งค่าด่วน"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"แถบงาน"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"แถบงานแสดงอยู่"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"แถบงานและบับเบิลแสดงไว้ทางซ้าย"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"แถบงานและบับเบิลแสดงไว้ทางขวา"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"แถบงานซ่อนอยู่"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"แถบงานและบับเบิลซ่อนอยู่"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"แถบนำทาง"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"แสดงแถบงานเสมอ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"เปลี่ยนโหมดการนําทาง"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index e1a77a5..88ebb4a 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"I-save ang app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pumili ng ibang app para gamitin ang split screen"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselahin"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Kanselahin"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Lumabas sa pagpili ng split screen"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pumili ng ibang app para gamitin ang split screen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ipinapakita ang taskbar"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar at bubble sa kaliwa"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar at bubble sa kanan"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Nakatago ang taskbar"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Nakatago ang taskbar at bubble"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Ipakita lagi ang Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Magpalit ng navigation mode"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index ef8f50d..6117bfd 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -90,7 +90,7 @@
     <string name="allset_title" msgid="5021126669778966707">"İşlem tamam!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Ana ekrana gitmek için yukarı kaydırın"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Ana ekranınıza gitmek için ana sayfa düğmesine dokunun"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızı kullanmaya hazırsınız"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> adlı cihazınızı kullanmaya hazırsınız"</string>
     <string name="default_device_name" msgid="6660656727127422487">"cihaz"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistem gezinme ayarları"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Paylaş"</string>
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Uygulama çiftini kaydet"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"İptal"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"İptal"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçiminden çıkın"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hızlı Ayarlar"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Görev çubuğu."</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Görev çubuğu gösteriliyor"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Görev çubuğu ve baloncuklar solda gösteriliyor"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Görev çubuğu ve baloncuklar sağda gösteriliyor"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Görev çubuğu gizlendi"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Görev çubuğu ve baloncuklar gizli"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Gezinme çubuğu"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Görev çubuğunu daima göster"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Gezinme modunu değiştir"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 201ac18..44170e9 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"Робочий стіл"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасувати"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Швидкі налаштув."</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель завдань"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панель завдань показано"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Панель завдань і чати – зліва"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Панель завдань і чати – справа"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панель завдань приховано"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Панель і чати приховано"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навігації"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Завжди показув. панель завдань"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Змінити режим навігації"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index b2a5c88..89cfbbb 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"منسوخ کریں"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"فوری ترتیبات"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ٹاسک بار"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ٹاشک بار دکھایا گیا"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ٹاسک بار و بلبلے بائیں طرف ہیں"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ٹاسک بار و بلبلے دائیں طرف ہیں"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ٹاسک بار چھپایا گیا"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ٹاسک بار اور بلبلے پوشیدہ ہیں"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نیویگیشن بار"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"ہمیشہ ٹاسک بار دکھائیں"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"نیویگیشن موڈ تبدیل کریں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 6df0b31..e3c7727 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Ilova juftini saqlash"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Bekor qilish"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Bekor qilish"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ekranni ikkiga ajratish tanlovidan chiqish"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Tezkor sozlamalar"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Vazifalar paneli"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Vazifalar paneli ochiq"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel va bulutchalar chapda"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel va bulutchalar oʻngda"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Vazifalar paneli yopiq"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel va bulutchalar berk"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatsiya paneli"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Vazifalar paneli doim chiqarilsin"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigatsiya rejimini oʻzgartirish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 76eec0c..8844fe9 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -99,7 +99,7 @@
     <string name="action_save_app_pair" msgid="5974823919237645229">"Lưu cặp ứng dụng"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Huỷ"</b></string>
+    <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Huỷ"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Thoát khỏi lựa chọn chia đôi màn hình"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cài đặt nhanh"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"Thanh tác vụ"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Đã hiện thanh thao tác"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Hiện thanh tác vụ, b.bóng trái"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Hiện thanh tác vụ, b.bóng phải"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Đã ẩn thanh thao tác"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Đã ẩn thanh tác vụ &amp; bong bóng"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Thanh điều hướng"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Luôn hiện Thanh tác vụ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Thay đổi chế độ điều hướng"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b5ae26d..b52d33b 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"桌面"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快捷设置"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"任务栏"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"任务栏已显示"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"已显示任务栏和左侧消息气泡"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"已显示任务栏和右侧消息气泡"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"任务栏已隐藏"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"已隐藏任务栏和消息气泡"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"导航栏"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"始终显示任务栏"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"更改导航模式"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index dd52065..a048848 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -99,7 +99,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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+    <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>
@@ -130,13 +130,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"顯示咗工作列"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"工作列和對話氣泡在左邊顯示"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"工作列和對話氣泡在右邊顯示"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"隱藏咗工作列"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"工作列和對話氣泡已隱藏"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"變更導覽模式"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 6d7652a..a27f2c5 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_option_desktop" msgid="8280879717125435668">"桌面"</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,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"已顯示工作列"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"工作列和對話框顯示在左側"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"工作列和對話框顯示在右側"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"已隱藏工作列"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"已隱藏工作列和對話框"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"變更操作模式"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 973ce80..b5f6abc 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -99,7 +99,8 @@
     <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>
-    <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Khansela"</b></string>
+    <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+    <skip />
     <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>
@@ -130,13 +131,10 @@
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Amasethingi Asheshayo"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"I-Taskbar"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ibha yomsebenzi ibonisiwe"</string>
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
-    <skip />
-    <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
-    <skip />
+    <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ITaskbar namabhamuza aboniswe kwesokunxele"</string>
+    <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ITaskbar namabhamuza aboniswe kwesokudla"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Ibha yomsebenzi ifihliwe"</string>
-    <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
-    <skip />
+    <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ITaskbar namabhamuza afihliwe"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Ibha yokufuna"</string>
     <string name="always_show_taskbar" msgid="3608801276107751229">"Bonisa i-Taskbar njalo."</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Shintsha imodi yokufuna"</string>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index fd12210..e8cb5d5 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -35,7 +35,7 @@
     <string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
     <string name="plugin_manager_wrapper_class" translatable="false">com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl</string>
     <string name="taskbar_edu_tooltip_controller_class" translatable="false">com.android.launcher3.taskbar.TaskbarEduTooltipController</string>
-
+    <string name="contextual_edu_manager_class" translatable="false">com.android.quickstep.contextualeducation.SystemContextualEduStatsManager</string>
     <string name="nav_handle_long_press_handler_class" translatable="false"></string>
     <string name="assist_utils_class" translatable="false"></string>
     <string name="assist_state_manager_class" translatable="false"></string>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 8bcbb33..d0f474f 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -26,9 +26,12 @@
     <string name="recent_task_option_pin">Pin</string>
     <!-- Title for an option to enter freeform mode for a given app -->
     <string name="recent_task_option_freeform">Freeform</string>
-    <!-- Title for an option to enter desktop windowing mode for a given app -->
+    <!-- Title and content description for an option to enter desktop windowing mode for a given app -->
     <string name="recent_task_option_desktop">Desktop</string>
 
+    <!-- Title and content description for Desktop tile in Recents screen that contains apps opened inside desktop windowing mode [CHAR LIMIT=NONE] -->
+    <string name="recent_task_desktop">Desktop</string>
+
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">No recent items</string>
 
@@ -237,7 +240,7 @@
     <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
     <string name="toast_split_select_app">Tap another app to use split screen</string>
     <string name="toast_contextual_split_select_app">Choose another app to use split screen</string>
-    <string name="toast_split_select_app_cancel"><b>Cancel</b></string>
+    <string name="toast_split_select_app_cancel">Cancel</string>
     <string name="toast_split_select_cont_desc">Exit split screen selection</string>
     <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
     <string name="toast_split_app_unsupported">Choose another app to use split screen</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index fe1b403..4a1035f 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -356,14 +356,6 @@
         options.setOnAnimationAbortListener(endCallback);
         options.setOnAnimationFinishedListener(endCallback);
 
-        // Prepare taskbar for animation synchronization. This needs to happen here before any
-        // app transition is created.
-        LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
-        if (enableScalingRevealHomeAnimation() && taskbarController != null) {
-            taskbarController.setIgnoreInAppFlagForSync(true);
-            onEndCallback.add(() -> taskbarController.setIgnoreInAppFlagForSync(false));
-        }
-
         IBinder cookie = mAppLaunchRunner.supportsReturnTransition()
                 ? ((ContainerAnimationRunner) mAppLaunchRunner).getCookie() : null;
         addLaunchCookie(cookie, (ItemInfo) v.getTag(), options);
@@ -1942,21 +1934,6 @@
                 anim.addListener(mForceInvisibleListener);
             }
 
-            // Syncs the app launch animation and taskbar stash animation (if exists).
-            if (enableScalingRevealHomeAnimation()) {
-                LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
-                if (taskbarController != null) {
-                    taskbarController.setIgnoreInAppFlagForSync(false);
-
-                    if (launcherClosing) {
-                        Animator taskbar = taskbarController.createAnimToApp();
-                        if (taskbar != null) {
-                            anim.play(taskbar);
-                        }
-                    }
-                }
-            }
-
             result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
                     skipFirstFrame);
         }
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 9178062..189deda 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -44,11 +44,13 @@
     /** Launch desktop tasks from recents view */
     fun launchDesktopFromRecents(
         desktopTaskView: DesktopTaskView,
+        animated: Boolean,
         callback: Consumer<Boolean>? = null
     ) {
         val animRunner =
             RemoteDesktopLaunchTransitionRunner(
                 desktopTaskView,
+                animated,
                 stateManager,
                 depthController,
                 callback
@@ -64,6 +66,7 @@
 
     private class RemoteDesktopLaunchTransitionRunner(
         private val desktopTaskView: DesktopTaskView,
+        private val animated: Boolean,
         private val stateManager: StateManager<*, *>,
         private val depthController: DepthController?,
         private val successCallback: Consumer<Boolean>?
@@ -84,16 +87,21 @@
             }
 
             MAIN_EXECUTOR.execute {
-                TaskViewUtils.composeRecentsDesktopLaunchAnimator(
-                    desktopTaskView,
-                    stateManager,
-                    depthController,
-                    info,
-                    t
-                ) {
-                    errorHandlingFinishCallback.run()
-                    successCallback?.accept(true)
+                val animator =
+                    TaskViewUtils.composeRecentsDesktopLaunchAnimator(
+                        desktopTaskView,
+                        stateManager,
+                        depthController,
+                        info,
+                        t
+                    ) {
+                        errorHandlingFinishCallback.run()
+                        successCallback?.accept(true)
+                    }
+                if (!animated) {
+                    animator.setDuration(0)
                 }
+                animator.start()
             }
         }
     }
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 6c7fe5b..644705b 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.Launcher;
@@ -38,6 +39,7 @@
 
 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
@@ -56,7 +58,7 @@
     private boolean mGestureInProgress;
 
     @Nullable
-    private IDesktopTaskListener mDesktopTaskListener;
+    private DesktopTaskListenerImpl mDesktopTaskListener;
 
     public DesktopVisibilityController(Launcher launcher) {
         mLauncher = launcher;
@@ -66,24 +68,7 @@
      * Register a listener with System UI to receive updates about desktop tasks state
      */
     public void registerSystemUiListener() {
-        mDesktopTaskListener = new IDesktopTaskListener.Stub() {
-            @Override
-            public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
-                MAIN_EXECUTOR.execute(() -> {
-                    if (displayId == mLauncher.getDisplayId()) {
-                        if (DEBUG) {
-                            Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
-                        }
-                        setVisibleDesktopTasksCount(visibleTasksCount);
-                    }
-                });
-            }
-
-            @Override
-            public void onStashedChanged(int displayId, boolean stashed) {
-              Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
-            }
-        };
+        mDesktopTaskListener = new DesktopTaskListenerImpl(this, mLauncher.getDisplayId());
         SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener);
     }
 
@@ -92,6 +77,7 @@
      */
     public void unregisterSystemUiListener() {
         SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null);
+        mDesktopTaskListener.release();
         mDesktopTaskListener = null;
     }
 
@@ -355,4 +341,43 @@
          */
         void onDesktopVisibilityChanged(boolean visible);
     }
+
+    /**
+     * Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher
+     * activity via the controller.
+     */
+    private static class DesktopTaskListenerImpl extends IDesktopTaskListener.Stub {
+
+        private DesktopVisibilityController mController;
+        private final int mDisplayId;
+
+        DesktopTaskListenerImpl(@NonNull DesktopVisibilityController controller, int displayId) {
+            mController = controller;
+            mDisplayId = displayId;
+        }
+
+        /**
+         * Clears any references to the controller.
+         */
+        void release() {
+            mController = null;
+        }
+
+        @Override
+        public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
+            MAIN_EXECUTOR.execute(() -> {
+                if (mController != null && displayId == mDisplayId) {
+                    if (DEBUG) {
+                        Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
+                    }
+                    mController.setVisibleDesktopTasksCount(visibleTasksCount);
+                }
+            });
+        }
+
+        @Override
+        public void onStashedChanged(int displayId, boolean stashed) {
+            Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index c201236..a833ccf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -16,19 +16,24 @@
 package com.android.launcher3.taskbar;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.SystemUiProxy;
 
 import java.util.ArrayList;
 import java.util.List;
 
 // TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
 /** Base for common behavior between taskbar window contexts. */
-public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext {
+public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext,
+        SystemShortcut.BubbleActivityStarter {
 
     protected final LayoutInflater mLayoutInflater;
     private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
@@ -48,6 +53,18 @@
         return mDPChangeListeners;
     }
 
+    @Override
+    public void showShortcutBubble(ShortcutInfo info) {
+        if (info == null) return;
+        SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
+    }
+
+    @Override
+    public void showAppBubble(Intent intent) {
+        if (intent == null || intent.getPackage() == null) return;
+        SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
+    }
+
     /** Callback invoked when a drag is initiated within this context. */
     public abstract void onDragStart();
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 0ba5de1..dbd9c73 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -54,6 +54,7 @@
 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;
@@ -213,9 +214,16 @@
                         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(
-                        groupTask.task1,
-                        groupTask.task2,
+                        leftTopTask,
+                        rightBottomTask,
                         updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
                         updateTasks ? mViewCallbacks::updateIconInBackground : null);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 3981e43..8df2eb8 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.launcher3.taskbar.TaskbarStashController.FLAG_IGNORE_IN_APP;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
 
@@ -225,9 +224,12 @@
         // Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
         // avoid updating taskbar state in that situation (when it's non-interactive -- or
         // "background") to avoid premature animations.
-        if (ENABLE_SHELL_TRANSITIONS && isVisible
-                && mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)
-                && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
+        LauncherState state = mLauncher.getStateManager().getState();
+        boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
+                && !state.isTaskbarAlignedWithHotseat(mLauncher);
+        if ((ENABLE_SHELL_TRANSITIONS
+                && isVisible
+                && (nonInteractiveState || mSkipLauncherVisibilityChange))) {
             return null;
         }
 
@@ -276,28 +278,6 @@
         return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
     }
 
-    /**
-     * Create Taskbar animation to be played alongside the Launcher app launch animation.
-     */
-    public @Nullable Animator createAnimToApp() {
-        TaskbarStashController stashController = mControllers.taskbarStashController;
-        stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
-        return stashController.createApplyStateAnimator(stashController.getStashDuration());
-    }
-
-    /**
-     * Temporarily ignore FLAG_IN_APP for app launches to prevent premature taskbar stashing.
-     * This is needed because taskbar gets a signal to stash before we actually start the
-     * app launch animation.
-     */
-    public void setIgnoreInAppFlagForSync(boolean enabled) {
-        if (mControllers == null) {
-            // This method can be called before init() is called.
-            return;
-        }
-        mControllers.taskbarStashController.updateStateForFlag(FLAG_IGNORE_IN_APP, enabled);
-    }
-
     public void updateTaskbarLauncherStateGoingHome() {
         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, true);
         mTaskbarLauncherStateController.applyState();
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index ea2adcf..f61840a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -264,11 +264,19 @@
         boolean isThreeButtonNav = mContext.isThreeButtonNav();
         DeviceProfile deviceProfile = mContext.getDeviceProfile();
         Resources resources = mContext.getResources();
-        Point p = !mContext.isUserSetupComplete()
-                ? new Point(0, mControllers.taskbarActivityContext.getSetupWindowSize())
-                : DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
-                        mContext.isPhoneMode());
-        mNavButtonsView.getLayoutParams().height = p.y;
+
+        int setupSize = mControllers.taskbarActivityContext.getSetupWindowSize();
+        Point p = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
+                mContext.isPhoneMode(), mContext.isGestureNav());
+        ViewGroup.LayoutParams navButtonsViewLayoutParams = mNavButtonsView.getLayoutParams();
+        navButtonsViewLayoutParams.width = p.x;
+        if (!mContext.isUserSetupComplete()) {
+            // Setup mode in phone mode uses gesture nav.
+            navButtonsViewLayoutParams.height = setupSize;
+        } else {
+            navButtonsViewLayoutParams.height = p.y;
+        }
+        mNavButtonsView.setLayoutParams(navButtonsViewLayoutParams);
 
         mIsImeRenderingNavButtons =
                 InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar();
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 266d0b9..475b516 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -212,7 +212,7 @@
      *                                stashed handle to wrap around the hotseat items.
      */
     public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) {
-        Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+        Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
         float startRadius = mStashedHandleRadius;
 
         if (DisplayController.isTransientTaskbar(mActivity)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f579d86..cd1eea2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -25,6 +25,7 @@
 import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
 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;
@@ -108,11 +109,16 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarView;
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleCreator;
 import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
 import com.android.launcher3.taskbar.bubbles.BubbleDragController;
 import com.android.launcher3.taskbar.bubbles.BubblePinController;
-import com.android.launcher3.taskbar.bubbles.BubbleStashController;
 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider;
+import com.android.launcher3.taskbar.bubbles.stashing.DeviceProfileDimensionsProviderAdapter;
+import com.android.launcher3.taskbar.bubbles.stashing.PersistentBubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.TransientBubbleStashController;
 import com.android.launcher3.taskbar.customization.TaskbarFeatureEvaluator;
 import com.android.launcher3.taskbar.customization.TaskbarSpecsEvaluator;
 import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
@@ -141,6 +147,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
@@ -150,6 +157,7 @@
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 import com.android.systemui.unfold.updates.RotationChangeProvider;
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
+import com.android.wm.shell.Flags;
 
 import java.io.PrintWriter;
 import java.util.Collections;
@@ -250,15 +258,18 @@
         mWindowManager = c.getSystemService(WindowManager.class);
 
         // Inflate views.
-        int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
-                ? R.layout.transient_taskbar
-                : R.layout.taskbar;
+        final boolean isTransientTaskbar = DisplayController.isTransientTaskbar(this)
+                && !isPhoneMode();
+        int taskbarLayout = isTransientTaskbar ? R.layout.transient_taskbar : R.layout.taskbar;
         mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
         NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
         StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
-        BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
+        BubbleBarView bubbleBarView = null;
+        if (isTransientTaskbar || Flags.enableBubbleBarInPersistentTaskBar()) {
+            bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
+        }
         StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
 
         mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
@@ -267,17 +278,28 @@
         Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
         BubbleBarController.onTaskbarRecreated();
         if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
+            Optional<BubbleStashedHandleViewController> bubbleHandleController = Optional.empty();
+            if (isTransientTaskbar) {
+                bubbleHandleController = Optional.of(
+                        new BubbleStashedHandleViewController(this, bubbleHandleView));
+            }
+            TaskbarHotseatDimensionsProvider dimensionsProvider =
+                    new DeviceProfileDimensionsProviderAdapter(this);
+            BubbleStashController bubbleStashController = isTransientTaskbar
+                    ? new TransientBubbleStashController(dimensionsProvider, getResources())
+                    : new PersistentBubbleStashController(dimensionsProvider);
             bubbleControllersOptional = Optional.of(new BubbleControllers(
                     new BubbleBarController(this, bubbleBarView),
                     new BubbleBarViewController(this, bubbleBarView),
-                    new BubbleStashController(this),
-                    new BubbleStashedHandleViewController(this, bubbleHandleView),
+                    bubbleStashController,
+                    bubbleHandleController,
                     new BubbleDragController(this),
                     new BubbleDismissController(this, mDragLayer),
                     new BubbleBarPinController(this, mDragLayer,
                             () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
                     new BubblePinController(this, mDragLayer,
-                            () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)
+                            () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
+                    new BubbleCreator(this)
             ));
         }
 
@@ -906,7 +928,7 @@
         mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
                 fromInit);
         boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
-        onNotificationShadeExpandChanged(isShadeVisible, fromInit);
+        onNotificationShadeExpandChanged(isShadeVisible, fromInit || isPhoneMode());
         mControllers.taskbarViewController.setRecentsButtonDisabled(
                 mControllers.navbarButtonsViewController.isRecentsDisabled()
                         || isNavBarKidsModeActive());
@@ -925,8 +947,9 @@
         mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags);
         mControllers.bubbleControllers.ifPresent(controllers -> {
             controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags);
-            controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled(
-                    mControllers.navbarButtonsViewController.isHomeDisabled());
+            controllers.bubbleStashedHandleViewController.ifPresent(controller ->
+                    controller.setIsHomeButtonDisabled(
+                            mControllers.navbarButtonsViewController.isHomeDisabled()));
         });
     }
 
@@ -964,6 +987,7 @@
     public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
         mControllers.navbarButtonsViewController.onTransitionModeUpdated(barMode, checkBarModes);
     }
+
     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
         mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
                 .updateValue(darkIntensity);
@@ -1113,6 +1137,9 @@
      * window.
      */
     public void setTaskbarWindowFocusable(boolean focusable) {
+        if (isPhoneMode()) {
+            return;
+        }
         if (focusable) {
             mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
         } else {
@@ -1125,7 +1152,7 @@
      * Applies forcibly show flag to taskbar window iff transient taskbar is unstashed.
      */
     public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
-        if (!DisplayController.isTransientTaskbar(this)) {
+        if (!DisplayController.isTransientTaskbar(this) || isPhoneMode()) {
             return;
         }
         if (shouldForceShow) {
@@ -1392,7 +1419,8 @@
                     if (foundTask != null) {
                         TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
                         if (foundTaskView != null
-                                && foundTaskView.isVisibleToUser()) {
+                                && foundTaskView.isVisibleToUser()
+                                && !(foundTaskView instanceof DesktopTaskView)) {
                             TestLogging.recordEvent(
                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
                             foundTaskView.launchTasks();
@@ -1443,7 +1471,6 @@
                         return;
                     }
                 }
-
                 startActivity(intent);
             } else {
                 getSystemService(LauncherApps.class).startMainActivity(
@@ -1488,6 +1515,12 @@
                 itemView.setHapticFeedbackEnabled(true);
                 return false;
             });
+
+            // Close any open taskbar tooltips.
+            if (AbstractFloatingView.hasOpenView(this, TYPE_ON_BOARD_POPUP)) {
+                AbstractFloatingView.getOpenView(this, TYPE_ON_BOARD_POPUP)
+                        .close(/* animate= */ false);
+            }
         });
     }
 
@@ -1668,7 +1701,7 @@
      * @param exclude {@code true} then the magnification region computation will omit the window.
      */
     public void excludeFromMagnificationRegion(boolean exclude) {
-        if (mIsExcludeFromMagnificationRegion == exclude) {
+        if (mIsExcludeFromMagnificationRegion == exclude || isPhoneMode()) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 0645972..d94d9175 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -165,6 +165,7 @@
         taskbarOverlayController.init(this);
         taskbarAllAppsController.init(this, sharedState.allAppsVisible);
         navButtonController.init(this);
+        bubbleControllers.ifPresent(controllers -> controllers.init(this));
         taskbarInsetsController.init(this);
         voiceInteractionWindowController.init(this);
         taskbarRecentAppsController.init(this);
@@ -172,7 +173,6 @@
         taskbarEduTooltipController.init(this);
         keyboardQuickSwitchController.init(this);
         taskbarPinningController.init(this, mSharedState);
-        bubbleControllers.ifPresent(controllers -> controllers.init(this));
 
         mControllersToLog = new LoggableTaskbarController[] {
                 taskbarDragController, navButtonController, navbarButtonsViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index ff890fb..acf976f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -291,7 +291,7 @@
             if (mActivity.isPhoneMode()) {
                 Resources resources = mActivity.getResources();
                 Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile,
-                        resources, true /* isPhoneMode */);
+                        resources, true /* isPhoneMode */, mActivity.isGestureNav());
                 return taskbarDimensions.y == -1 ?
                         deviceProfile.getDisplayInfo().currentSize.y :
                         taskbarDimensions.y;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 6ac862e..8a86402 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -85,6 +85,9 @@
 
     /** Update values tracked via sysui flags. */
     public void updateSysuiFlags(@SystemUiStateFlags long sysuiFlags) {
+        if (mContext.isPhoneMode()) {
+            return;
+        }
         mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0;
         if (mContext.isNavBarForceVisible()) {
             if (mIsImmersiveMode) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
index dd14109..8c7879d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
@@ -18,30 +18,22 @@
 import static android.view.MotionEvent.ACTION_HOVER_ENTER;
 import static android.view.MotionEvent.ACTION_HOVER_EXIT;
 import static android.view.View.ALPHA;
-import static android.view.View.SCALE_Y;
-import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT;
 
-import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_EXCEPT_ON_BOARD_POPUP;
+import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS;
-import static com.android.launcher3.views.ArrowTipView.TEXT_ALPHA;
 
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
 import android.view.ContextThemeWrapper;
 import android.view.MotionEvent;
 import android.view.View;
 
-import com.android.app.animation.Interpolators;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.apppairs.AppPairIcon;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.views.ArrowTipView;
 
@@ -49,13 +41,9 @@
  * Controls showing a tooltip in the taskbar above each icon when it is hovered.
  */
 public class TaskbarHoverToolTipController implements View.OnHoverListener {
-
-    private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 250;
-    private static final int HOVER_TOOL_TIP_EXIT_DURATION = 150;
-
-    private final Handler mHoverToolTipHandler = new Handler(Looper.getMainLooper());
-    private final Runnable mRevealHoverToolTipRunnable = this::revealHoverToolTip;
-    private final Runnable mHideHoverToolTipRunnable = this::hideHoverToolTip;
+    // Short duration to reveal tooltip, as it is positioned in the x/y via a post() call in
+    // parallel with the open animation. An instant animation could show in the wrong location.
+    private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 15;
 
     private final TaskbarActivityContext mActivity;
     private final TaskbarView mTaskbarView;
@@ -90,35 +78,11 @@
                 R.dimen.taskbar_tooltip_horizontal_padding);
         mHoverToolTipView.findViewById(R.id.text).setPadding(horizontalPadding, verticalPadding,
                 horizontalPadding, verticalPadding);
-
-        AnimatorSet hoverCloseAnimator = new AnimatorSet();
-        ObjectAnimator textCloseAnimator = ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0);
-        textCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0, 0.33f));
-        ObjectAnimator alphaCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0);
-        alphaCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.33f, 0.66f));
-        ObjectAnimator scaleCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0);
-        scaleCloseAnimator.setInterpolator(Interpolators.STANDARD);
-        hoverCloseAnimator.playTogether(
-                textCloseAnimator,
-                alphaCloseAnimator,
-                scaleCloseAnimator);
-        hoverCloseAnimator.setStartDelay(0);
-        hoverCloseAnimator.setDuration(HOVER_TOOL_TIP_EXIT_DURATION);
-        mHoverToolTipView.setCustomCloseAnimation(hoverCloseAnimator);
+        mHoverToolTipView.setAlpha(0);
 
         AnimatorSet hoverOpenAnimator = new AnimatorSet();
-        ObjectAnimator textOpenAnimator =
-                ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0, 255);
-        textOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.15f, 0.75f));
-        ObjectAnimator scaleOpenAnimator =
-                ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0f, 1f);
-        scaleOpenAnimator.setInterpolator(Interpolators.EMPHASIZED);
         ObjectAnimator alphaOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0f, 1f);
-        alphaOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0f, 0.33f));
-        hoverOpenAnimator.playTogether(
-                scaleOpenAnimator,
-                textOpenAnimator,
-                alphaOpenAnimator);
+        hoverOpenAnimator.play(alphaOpenAnimator);
         hoverOpenAnimator.setDuration(HOVER_TOOL_TIP_REVEAL_DURATION);
         mHoverToolTipView.setCustomOpenAnimation(hoverOpenAnimator);
 
@@ -131,28 +95,17 @@
 
     @Override
     public boolean onHover(View v, MotionEvent event) {
-        boolean isAnyOtherFloatingViewOpen =
-                AbstractFloatingView.hasOpenView(mActivity, TYPE_ALL_EXCEPT_ON_BOARD_POPUP);
-        if (isAnyOtherFloatingViewOpen) {
-            mHoverToolTipHandler.removeCallbacksAndMessages(null);
-        }
+        boolean isFolderOpen = AbstractFloatingView.hasOpenView(mActivity, TYPE_FOLDER);
         // If hover leaves a taskbar icon animate the tooltip closed.
         if (event.getAction() == ACTION_HOVER_EXIT) {
-            startHideHoverToolTip();
+            mHoverToolTipView.close(/* animate= */ false);
             mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, false);
-            return true;
-        } else if (!isAnyOtherFloatingViewOpen && event.getAction() == ACTION_HOVER_ENTER) {
-            // If hovering above a taskbar icon starts, animate the tooltip open. Do not
-            // reveal if any floating views such as folders or edu pop-ups are open.
-            startRevealHoverToolTip();
+        } else if (!isFolderOpen && event.getAction() == ACTION_HOVER_ENTER) {
+            // Do not reveal if any floating views such as folders or edu pop-ups are open.
+            revealHoverToolTip();
             mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, true);
-            return true;
         }
-        return false;
-    }
-
-    private void startRevealHoverToolTip() {
-        mHoverToolTipHandler.post(mRevealHoverToolTipRunnable);
+        return true;
     }
 
     private void revealHoverToolTip() {
@@ -170,14 +123,4 @@
         mHoverToolTipView.showAtLocation(mToolTipText, iconViewBounds.centerX(),
                 mTaskbarView.getTop(), /* shouldAutoClose= */ false);
     }
-
-    private void startHideHoverToolTip() {
-        int accessibilityHideTimeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(
-                mActivity, /* originalTimeout= */ 0, FLAG_CONTENT_TEXT);
-        mHoverToolTipHandler.postDelayed(mHideHoverToolTipRunnable, accessibilityHideTimeout);
-    }
-
-    private void hideHoverToolTip() {
-        mHoverToolTipView.close(/* animate = */ true);
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 2103ebb..9dee473 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -64,6 +64,10 @@
     companion object {
         private const val INDEX_LEFT = 0
         private const val INDEX_RIGHT = 1
+
+        private fun Region.addBoundsToRegion(bounds: Rect?) {
+            bounds?.let { op(it, Region.Op.UNION) }
+        }
     }
 
     /** The bottom insets taskbar provides to the IME when IME is visible. */
@@ -128,46 +132,25 @@
             }
         }
 
+        val bubbleControllers = controllers.bubbleControllers.getOrNull()
         val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
         val bubblesTouchableHeight =
-            if (controllers.bubbleControllers.isPresent) {
-                controllers.bubbleControllers.get().bubbleStashController.touchableHeight
-            } else {
-                0
-            }
+            bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
+        // add bounds for task bar and bubble bar stash controllers
         val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
-
-        if (
-            controllers.bubbleControllers.isPresent &&
-                controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome
-        ) {
-            val iconBounds =
-                controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
-            defaultTouchableRegion.set(
-                iconBounds.left,
-                iconBounds.top,
-                iconBounds.right,
-                iconBounds.bottom
-            )
-        } else {
-            defaultTouchableRegion.set(
-                0,
-                windowLayoutParams.height - touchableHeight,
-                context.deviceProfile.widthPx,
-                windowLayoutParams.height
-            )
-
-            // if there's an animating bubble add it to the touch region so that it's clickable
-            val isAnimatingNewBubble =
-                controllers.bubbleControllers
-                    .getOrNull()
-                    ?.bubbleBarViewController
-                    ?.isAnimatingNewBubble
-                    ?: false
-            if (isAnimatingNewBubble) {
-                val iconBounds =
-                    controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
-                defaultTouchableRegion.op(iconBounds, Region.Op.UNION)
+        defaultTouchableRegion.set(
+            0,
+            windowLayoutParams.height - touchableHeight,
+            context.deviceProfile.widthPx,
+            windowLayoutParams.height
+        )
+        if (bubbleControllers != null) {
+            val bubbleBarViewController = bubbleControllers.bubbleBarViewController
+            val isBubbleBarVisible = bubbleControllers.bubbleStashController.isBubbleBarVisible()
+            val isAnimatingNewBubble = bubbleBarViewController.isAnimatingNewBubble
+            // if bubble bar is visible or animating new bubble, add bar bounds to the touch region
+            if (isBubbleBarVisible || isAnimatingNewBubble) {
+                defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
             }
         }
 
@@ -358,13 +341,6 @@
      */
     fun updateInsetsTouchability(insetsInfo: ViewTreeObserver.InternalInsetsInfo) {
         insetsInfo.touchableRegion.setEmpty()
-        // Always have nav buttons be touchable
-        controllers.navbarButtonsViewController.addVisibleButtonsRegion(
-            context.dragLayer,
-            insetsInfo.touchableRegion
-        )
-        debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
-
         val bubbleBarVisible =
             controllers.bubbleControllers.isPresent &&
                 controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
@@ -426,7 +402,7 @@
 
                 // Include the bounds of the bubble bar in the touchable region if they exist.
                 if (bubbleBarBounds != null) {
-                    region.op(bubbleBarBounds, Region.Op.UNION)
+                    region.addBoundsToRegion(bubbleBarBounds)
                 }
                 insetsInfo.touchableRegion.set(region)
                 debugTouchableRegion.lastSetTouchableReason = "Transient Taskbar is in Overview"
@@ -443,6 +419,12 @@
             debugTouchableRegion.lastSetTouchableReason =
                 "Icons are not visible, but other components such as 3 buttons might be"
         }
+        // Always have nav buttons be touchable
+        controllers.navbarButtonsViewController.addVisibleButtonsRegion(
+            context.dragLayer,
+            insetsInfo.touchableRegion
+        )
+        debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
         context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 20ab32e..e6b3acd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -470,7 +470,8 @@
                 // We're changing state to home, should close open popups e.g. Taskbar AllApps
                 handleOpenFloatingViews = true;
             }
-            if (mLauncherState == LauncherState.OVERVIEW) {
+            if (mLauncherState == LauncherState.OVERVIEW
+                    && !mControllers.taskbarActivityContext.isPhoneMode()) {
                 // Calling to update the insets in TaskbarInsetController#updateInsetsTouchability
                 mControllers.taskbarActivityContext.notifyUpdateLayoutParams();
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index b697590..332eb95 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -53,6 +53,7 @@
 import com.android.quickstep.util.LogUtils;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Objects;
@@ -69,6 +70,9 @@
     private static final SystemShortcut.Factory<BaseTaskbarContext>
             APP_INFO = SystemShortcut.AppInfo::new;
 
+    private static final SystemShortcut.Factory<BaseTaskbarContext>
+            BUBBLE = SystemShortcut.BubbleShortcut::new;
+
     private final TaskbarActivityContext mContext;
     private final PopupDataProvider mPopupDataProvider;
 
@@ -181,11 +185,17 @@
 
     // Create a Stream of all applicable system shortcuts
     private Stream<SystemShortcut.Factory> getSystemShortcuts() {
-        // append split options to APP_INFO shortcut, the order here will reflect in the popup
-        return Stream.concat(
-                Stream.of(APP_INFO),
-                mControllers.uiController.getSplitMenuOptions()
-        );
+        // append split options to APP_INFO shortcut if not in Desktop Windowing mode, the order
+        // here will reflect in the popup
+        ArrayList<SystemShortcut.Factory> shortcuts = new ArrayList<>();
+        shortcuts.add(APP_INFO);
+        if (!mControllers.taskbarRecentAppsController.isInDesktopMode()) {
+            shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList());
+        }
+        if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+            shortcuts.add(BUBBLE);
+        }
+        return shortcuts.stream();
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 6b5e51f..737d031 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -27,7 +27,7 @@
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.GroupTask
-import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import java.io.PrintWriter
 
@@ -45,7 +45,8 @@
 ) : LoggableTaskbarController {
 
     var canShowRunningApps =
-        DesktopModeStatus.canEnterDesktopMode(context) && enableDesktopWindowingTaskbarRunningApps()
+        DesktopModeStatus.canEnterDesktopMode(context) &&
+            DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(context)
         @VisibleForTesting
         set(isEnabledFromTest) {
             field = isEnabledFromTest
@@ -80,7 +81,7 @@
     private val desktopVisibilityController: DesktopVisibilityController?
         get() = desktopVisibilityControllerProvider()
 
-    private val isInDesktopMode: Boolean
+    val isInDesktopMode: Boolean
         get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
 
     val runningTaskIds: Set<Int>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 5e7c7ce..4df0223 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -28,6 +28,7 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -86,6 +87,10 @@
      * Updates the scrim state based on the flags.
      */
     public void updateStateForSysuiFlags(@SystemUiStateFlags long stateFlags, boolean skipAnim) {
+        if (mActivity.isPhoneMode()) {
+            // There is no scrim for the bar in the phone mode.
+            return;
+        }
         if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) {
             // These scrims aren't used if bubble bar & transient taskbar are active.
             return;
@@ -97,10 +102,20 @@
     private boolean shouldShowScrim() {
         final boolean bubblesExpanded = (mSysUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
         boolean isShadeVisible = (mSysUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
+        BubbleControllers bubbleControllers = mActivity.getBubbleControllers();
+        boolean isBubbleControllersPresented = bubbleControllers != null;
+        // when the taskbar is in persistent mode, we hide the task bar icons on bubble bar expand,
+        // which makes the taskbar invisible, so need to check if the bubble bar is not on home
+        // to show the scrim view
+        boolean showScrimForBubbles = bubblesExpanded
+                && !mTaskbarVisible
+                && isBubbleControllersPresented
+                && !DisplayController.isTransientTaskbar(mActivity)
+                && !bubbleControllers.bubbleStashController.isBubblesShowingOnHome();
         return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible()
                 && !isShadeVisible
                 && !mControllers.taskbarStashController.isStashed()
-                && mTaskbarVisible;
+                && (mTaskbarVisible || showScrimForBubbles);
     }
 
     private float getScrimAlpha() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 5d6fdc1..8a20131 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -96,7 +96,6 @@
     public static final int FLAG_STASHED_SYSUI = 1 << 9; //  app pinning,...
     public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 10; // device is locked: keyguard, ...
     public static final int FLAG_IN_OVERVIEW = 1 << 11; // launcher is in overview
-    public static final int FLAG_IGNORE_IN_APP = 1 << 12; // used to sync with app launch animation
 
     // If any of these flags are enabled, isInApp should return true.
     private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -1022,6 +1021,10 @@
 
     /** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
     public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) {
+        if (mActivity.isPhoneMode()) {
+            return;
+        }
+
         long animDuration = TASKBAR_STASH_DURATION;
         long startDelay = 0;
 
@@ -1281,11 +1284,6 @@
          */
         @Nullable
         public Animator createSetStateAnimator(long flags, long duration) {
-            // We do this when we want to synchronize the app launch and taskbar stash animations.
-            if (hasAnyFlag(FLAG_IGNORE_IN_APP) && hasAnyFlag(flags, FLAG_IN_APP)) {
-                flags = flags & ~FLAG_IN_APP;
-            }
-
             boolean isStashed = mStashCondition.test(flags);
 
             if (DEBUG) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 144c0c2..5a5d6d0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -95,7 +95,8 @@
         mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
         mControllers.bubbleControllers.ifPresent(controllers -> {
             controllers.bubbleBarViewController.setTranslationYForSwipe(transY);
-            controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY);
+            controllers.bubbleStashedHandleViewController.ifPresent(
+                    controller -> controller.setTranslationYForSwipe(transY));
         });
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index a2278ec..42bf8db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -61,6 +61,8 @@
     // Initialized in init.
     protected TaskbarControllers mControllers;
 
+    protected boolean mSkipLauncherVisibilityChange;
+
     @CallSuper
     protected void init(TaskbarControllers taskbarControllers) {
         mControllers = taskbarControllers;
@@ -174,11 +176,11 @@
                 || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
     }
 
-    /** Checks if the given {@link MotionEvent} is over the bubble bar stash handle. */
-    public boolean isEventOverBubbleBarStashHandle(MotionEvent ev) {
+    /** Checks if the given {@link MotionEvent} is over the bubble bar views. */
+    public boolean isEventOverBubbleBarViews(MotionEvent ev) {
         return mControllers.bubbleControllers.map(
                 bubbleControllers ->
-                        bubbleControllers.bubbleStashController.isEventOverStashHandle(ev))
+                        bubbleControllers.bubbleStashController.isEventOverBubbleBarViews(ev))
                 .orElse(false);
     }
 
@@ -418,4 +420,12 @@
     public void setUserIsNotGoingHome(boolean isNotGoingHome) {
         mControllers.taskbarStashController.setUserIsNotGoingHome(isNotGoingHome);
     }
+
+    /**
+     * Sets whether to prevent taskbar from reacting to launcher visibility during the recents
+     * transition animation.
+     */
+    public void setSkipLauncherVisibilityChange(boolean skip) {
+        mSkipLauncherVisibilityChange = skip;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index e58069a..fc76972 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -669,8 +669,20 @@
         return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
     }
 
+    /**
+     * Gets visual bounds of the taskbar view. The visual bounds correspond to the taskbar touch
+     * area, rather than layout placement in the parent view.
+     */
+    public Rect getIconLayoutVisualBounds() {
+        return new Rect(mIconLayoutBounds);
+    }
+
+    /** Gets taskbar layout bounds in parent view. */
     public Rect getIconLayoutBounds() {
-        return mIconLayoutBounds;
+        Rect actualBounds = new Rect(mIconLayoutBounds);
+        actualBounds.top = getTop();
+        actualBounds.bottom = getBottom();
+        return actualBounds;
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index ffa4819..b8b85d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -96,7 +96,9 @@
     public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
     public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5;
     public static final int ALPHA_INDEX_SMALL_SCREEN = 6;
-    private static final int NUM_ALPHA_CHANNELS = 7;
+
+    public static final int ALPHA_INDEX_BUBBLE_BAR = 7;
+    private static final int NUM_ALPHA_CHANNELS = 8;
 
     private static boolean sEnableModelLoadingForTests = true;
 
@@ -272,6 +274,10 @@
         OneShotPreDrawListener.add(mTaskbarView, listener);
     }
 
+    public Rect getIconLayoutVisualBounds() {
+        return mTaskbarView.getIconLayoutVisualBounds();
+    }
+
     public Rect getIconLayoutBounds() {
         return mTaskbarView.getIconLayoutBounds();
     }
@@ -462,14 +468,14 @@
         if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
             float transY =
                     mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
-                            - mTaskbarView.getIconLayoutBounds().bottom)
+                            - mTaskbarView.getIconLayoutVisualBounds().bottom)
                             - (mPersistentTaskbarDp.taskbarHeight
                                     - mTransientTaskbarDp.taskbarIconSize) / 2f;
             taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
         } else {
             float transY =
                     -mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
-                            - mTaskbarView.getIconLayoutBounds().bottom)
+                            - mTaskbarView.getIconLayoutVisualBounds().bottom)
                             - (mTransientTaskbarDp.taskbarHeight
                                     - mTransientTaskbarDp.taskbarIconSize) / 2f;
             taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index 619c9c4..c380c8d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -110,7 +110,7 @@
     }
 
     fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
-        if (isVoiceInteractionWindowVisible == visible) {
+        if (isVoiceInteractionWindowVisible == visible || context.isPhoneMode) {
             return
         }
         isVoiceInteractionWindowVisible = visible
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 5be0171..a36d5f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -15,13 +15,8 @@
  */
 package com.android.launcher3.taskbar.bubbles;
 
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_PERSONS_DATA;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 
-import static com.android.launcher3.icons.FastBitmapDrawable.WHITE_SCRIM_ALPHA;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -34,35 +29,13 @@
 import android.annotation.BinderThread;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Path;
 import android.graphics.Point;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.os.Bundle;
 import android.os.SystemProperties;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.PathParser;
-import android.view.LayoutInflater;
 
-import androidx.appcompat.content.res.AppCompatResources;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.BubbleIconFactory;
-import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
 import com.android.launcher3.util.Executors.SimpleThreadFactory;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -76,6 +49,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 
@@ -134,18 +108,16 @@
 
     private static final Executor BUBBLE_STATE_EXECUTOR = Executors.newSingleThreadExecutor(
             new SimpleThreadFactory("BubbleStateUpdates-", THREAD_PRIORITY_BACKGROUND));
-    private final LauncherApps mLauncherApps;
-    private final BubbleIconFactory mIconFactory;
     private final SystemUiProxy mSystemUiProxy;
 
     private BubbleBarItem mSelectedBubble;
-    private BubbleBarOverflow mOverflowBubble;
 
     private ImeVisibilityChecker mImeVisibilityChecker;
     private BubbleBarViewController mBubbleBarViewController;
     private BubbleStashController mBubbleStashController;
-    private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
+    private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController;
     private BubblePinController mBubblePinController;
+    private BubbleCreator mBubbleCreator;
 
     // Cache last sent top coordinate to avoid sending duplicate updates to shell
     private int mLastSentBubbleBarTop;
@@ -166,6 +138,8 @@
         List<RemovedBubble> removedBubbles;
         List<String> bubbleKeysInOrder;
         Point expandedViewDropTargetSize;
+        boolean showOverflow;
+        boolean showOverflowChanged;
 
         // These need to be loaded in the background
         BubbleBarBubble addedBubble;
@@ -184,6 +158,8 @@
             removedBubbles = update.removedBubbles;
             bubbleKeysInOrder = update.bubbleKeysInOrder;
             expandedViewDropTargetSize = update.expandedViewDropTargetSize;
+            showOverflow = update.showOverflow;
+            showOverflowChanged = update.showOverflowChanged;
         }
     }
 
@@ -192,17 +168,6 @@
         mBarView = bubbleView; // Need the view for inflating bubble views.
 
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(context);
-
-        if (sBubbleBarEnabled) {
-            mSystemUiProxy.setBubblesListener(this);
-        }
-        mLauncherApps = context.getSystemService(LauncherApps.class);
-        mIconFactory = new BubbleIconFactory(context,
-                context.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size),
-                context.getResources().getDimensionPixelSize(R.dimen.bubblebar_badge_size),
-                context.getResources().getColor(R.color.important_conversation),
-                context.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.importance_ring_stroke_width));
     }
 
     public void onDestroy() {
@@ -217,37 +182,22 @@
         mBubbleStashController = bubbleControllers.bubbleStashController;
         mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
         mBubblePinController = bubbleControllers.bubblePinController;
+        mBubbleCreator = bubbleControllers.bubbleCreator;
 
         bubbleControllers.runAfterInit(() -> {
             mBubbleBarViewController.setHiddenForBubbles(
                     !sBubbleBarEnabled || mBubbles.isEmpty());
-            mBubbleStashedHandleViewController.setHiddenForBubbles(
-                    !sBubbleBarEnabled || mBubbles.isEmpty());
+            mBubbleStashedHandleViewController.ifPresent(
+                    controller -> controller.setHiddenForBubbles(
+                            !sBubbleBarEnabled || mBubbles.isEmpty()));
             mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
                     key -> setSelectedBubbleInternal(mBubbles.get(key)));
             mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged);
-        });
-    }
 
-    /**
-     * Creates and adds the overflow bubble to the bubble bar if it hasn't been created yet.
-     *
-     * <p>This should be called on the {@link #BUBBLE_STATE_EXECUTOR} executor to avoid inflating
-     * the overflow multiple times.
-     */
-    private void createAndAddOverflowIfNeeded() {
-        if (mOverflowBubble == null) {
-            BubbleBarOverflow overflow = createOverflow(mContext);
-            MAIN_EXECUTOR.execute(() -> {
-                // we're on the main executor now, so check that the overflow hasn't been created
-                // again to avoid races.
-                if (mOverflowBubble == null) {
-                    mBubbleBarViewController.addBubble(
-                            overflow, /* isExpanding= */ false, /* suppressAnimation= */ true);
-                    mOverflowBubble = overflow;
-                }
-            });
-        }
+            if (sBubbleBarEnabled) {
+                mSystemUiProxy.setBubblesListener(this);
+            }
+        });
     }
 
     /**
@@ -258,10 +208,11 @@
         mBubbleBarViewController.setHiddenForSysui(hideBubbleBar);
 
         boolean hideHandleView = (flags & MASK_HIDE_HANDLE_VIEW) != 0;
-        mBubbleStashedHandleViewController.setHiddenForSysui(hideHandleView);
+        mBubbleStashedHandleViewController.ifPresent(
+                controller -> controller.setHiddenForSysui(hideHandleView));
 
         boolean sysuiLocked = (flags & MASK_SYSUI_LOCKED) != 0;
-        mBubbleStashController.onSysuiLockedStateChange(sysuiLocked);
+        mBubbleStashController.setSysuiLocked(sysuiLocked);
     }
 
     //
@@ -279,23 +230,25 @@
                 || !update.currentBubbleList.isEmpty()) {
             // We have bubbles to load
             BUBBLE_STATE_EXECUTOR.execute(() -> {
-                createAndAddOverflowIfNeeded();
                 if (update.addedBubble != null) {
-                    viewUpdate.addedBubble = populateBubble(mContext, update.addedBubble, mBarView,
+                    viewUpdate.addedBubble = mBubbleCreator.populateBubble(mContext,
+                            update.addedBubble,
+                            mBarView,
                             null /* existingBubble */);
                 }
                 if (update.updatedBubble != null) {
                     BubbleBarBubble existingBubble = mBubbles.get(update.updatedBubble.getKey());
                     viewUpdate.updatedBubble =
-                            populateBubble(mContext, update.updatedBubble, mBarView,
+                            mBubbleCreator.populateBubble(mContext, update.updatedBubble,
+                                    mBarView,
                                     existingBubble);
                 }
                 if (update.currentBubbleList != null && !update.currentBubbleList.isEmpty()) {
                     List<BubbleBarBubble> currentBubbles = new ArrayList<>();
                     for (int i = 0; i < update.currentBubbleList.size(); i++) {
-                        BubbleBarBubble b =
-                                populateBubble(mContext, update.currentBubbleList.get(i), mBarView,
-                                        null /* existingBubble */);
+                        BubbleBarBubble b = mBubbleCreator.populateBubble(mContext,
+                                update.currentBubbleList.get(i), mBarView,
+                                null /* existingBubble */);
                         currentBubbles.add(b);
                     }
                     viewUpdate.currentBubbles = currentBubbles;
@@ -322,25 +275,38 @@
 
         BubbleBarBubble bubbleToSelect = null;
 
-        if (update.addedBubble != null && update.removedBubbles.size() == 1) {
+        if (Flags.enableOptionalBubbleOverflow()
+                && update.showOverflowChanged && !update.showOverflow && update.addedBubble != null
+                && update.removedBubbles.isEmpty()) {
+            // A bubble was added from the overflow (& now it's empty / not showing)
+            mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+            mBubbleBarViewController.removeOverflowAndAddBubble(update.addedBubble);
+        } else if (update.addedBubble != null && update.removedBubbles.size() == 1) {
             // we're adding and removing a bubble at the same time. handle this as a single update.
             RemovedBubble removedBubble = update.removedBubbles.get(0);
             BubbleBarBubble bubbleToRemove = mBubbles.remove(removedBubble.getKey());
             mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+            boolean showOverflow = update.showOverflowChanged && update.showOverflow;
             if (bubbleToRemove != null) {
                 mBubbleBarViewController.addBubbleAndRemoveBubble(update.addedBubble,
-                        bubbleToRemove, isExpanding, suppressAnimation);
+                        bubbleToRemove, isExpanding, suppressAnimation, showOverflow);
             } else {
                 mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
                         suppressAnimation);
                 Log.w(TAG, "trying to remove bubble that doesn't exist: " + removedBubble.getKey());
             }
         } else {
+            boolean overflowNeedsToBeAdded = Flags.enableOptionalBubbleOverflow()
+                    && update.showOverflowChanged && update.showOverflow;
             if (!update.removedBubbles.isEmpty()) {
                 for (int i = 0; i < update.removedBubbles.size(); i++) {
                     RemovedBubble removedBubble = update.removedBubbles.get(i);
                     BubbleBarBubble bubble = mBubbles.remove(removedBubble.getKey());
-                    if (bubble != null) {
+                    if (bubble != null && overflowNeedsToBeAdded) {
+                        // First removal, show the overflow
+                        overflowNeedsToBeAdded = false;
+                        mBubbleBarViewController.addOverflowAndRemoveBubble(bubble);
+                    } else if (bubble != null) {
                         mBubbleBarViewController.removeBubble(bubble);
                     } else {
                         Log.w(TAG, "trying to remove bubble that doesn't exist: "
@@ -353,6 +319,11 @@
                 mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
                         suppressAnimation);
             }
+            if (Flags.enableOptionalBubbleOverflow()
+                    && update.showOverflowChanged
+                    && update.showOverflow != mBubbleBarViewController.isOverflowAdded()) {
+                mBubbleBarViewController.showOverflow(update.showOverflow);
+            }
         }
 
         // if a bubble was updated upstream, but removed before the update was received, add it back
@@ -384,10 +355,14 @@
                 }
             }
         }
+        if (Flags.enableOptionalBubbleOverflow() && update.initialState && update.showOverflow) {
+            mBubbleBarViewController.showOverflow(true);
+        }
 
         // Adds and removals have happened, update visibility before any other visual changes.
         mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
-        mBubbleStashedHandleViewController.setHiddenForBubbles(mBubbles.isEmpty());
+        mBubbleStashedHandleViewController.ifPresent(
+                controller -> controller.setHiddenForBubbles(mBubbles.isEmpty()));
 
         if (mBubbles.isEmpty()) {
             // all bubbles were removed. clear the selected bubble
@@ -525,133 +500,6 @@
     // Loading data for the bubbles
     //
 
-    @Nullable
-    private BubbleBarBubble populateBubble(Context context, BubbleInfo b, BubbleBarView bbv,
-            @Nullable BubbleBarBubble existingBubble) {
-        String appName;
-        Bitmap badgeBitmap;
-        Bitmap bubbleBitmap;
-        Path dotPath;
-        int dotColor;
-
-        boolean isImportantConvo = b.isImportantConversation();
-
-        ShortcutRequest.QueryResult result = new ShortcutRequest(context,
-                new UserHandle(b.getUserId()))
-                .forPackage(b.getPackageName(), b.getShortcutId())
-                .query(FLAG_MATCH_DYNAMIC
-                        | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
-                        | FLAG_MATCH_CACHED
-                        | FLAG_GET_PERSONS_DATA);
-
-        ShortcutInfo shortcutInfo = result.size() > 0 ? result.get(0) : null;
-        if (shortcutInfo == null) {
-            Log.w(TAG, "No shortcutInfo found for bubble: " + b.getKey()
-                    + " with shortcutId: " + b.getShortcutId());
-        }
-
-        ApplicationInfo appInfo;
-        try {
-            appInfo = mLauncherApps.getApplicationInfo(
-                    b.getPackageName(),
-                    0,
-                    new UserHandle(b.getUserId()));
-        } catch (PackageManager.NameNotFoundException e) {
-            // If we can't find package... don't think we should show the bubble.
-            Log.w(TAG, "Unable to find packageName: " + b.getPackageName());
-            return null;
-        }
-        if (appInfo == null) {
-            Log.w(TAG, "Unable to find appInfo: " + b.getPackageName());
-            return null;
-        }
-        PackageManager pm = context.getPackageManager();
-        appName = String.valueOf(appInfo.loadLabel(pm));
-        Drawable appIcon = appInfo.loadUnbadgedIcon(pm);
-        Drawable badgedIcon = pm.getUserBadgedIcon(appIcon, new UserHandle(b.getUserId()));
-
-        // Badged bubble image
-        Drawable bubbleDrawable = mIconFactory.getBubbleDrawable(context, shortcutInfo,
-                b.getIcon());
-        if (bubbleDrawable == null) {
-            // Default to app icon
-            bubbleDrawable = appIcon;
-        }
-
-        BitmapInfo badgeBitmapInfo = mIconFactory.getBadgeBitmap(badgedIcon, isImportantConvo);
-        badgeBitmap = badgeBitmapInfo.icon;
-
-        float[] bubbleBitmapScale = new float[1];
-        bubbleBitmap = mIconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
-
-        // Dot color & placement
-        Path iconPath = PathParser.createPathFromPathData(
-                context.getResources().getString(
-                        com.android.internal.R.string.config_icon_mask));
-        Matrix matrix = new Matrix();
-        float scale = bubbleBitmapScale[0];
-        float radius = BubbleView.DEFAULT_PATH_SIZE / 2f;
-        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
-                radius /* pivot y */);
-        iconPath.transform(matrix);
-        dotPath = iconPath;
-        dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
-                Color.WHITE, WHITE_SCRIM_ALPHA / 255f);
-
-        if (existingBubble == null) {
-            LayoutInflater inflater = LayoutInflater.from(context);
-            BubbleView bubbleView = (BubbleView) inflater.inflate(
-                    R.layout.bubblebar_item_view, bbv, false /* attachToRoot */);
-
-            BubbleBarBubble bubble = new BubbleBarBubble(b, bubbleView,
-                    badgeBitmap, bubbleBitmap, dotColor, dotPath, appName);
-            bubbleView.setBubble(bubble);
-            return bubble;
-        } else {
-            // If we already have a bubble (so it already has an inflated view), update it.
-            existingBubble.setInfo(b);
-            existingBubble.setBadge(badgeBitmap);
-            existingBubble.setIcon(bubbleBitmap);
-            existingBubble.setDotColor(dotColor);
-            existingBubble.setDotPath(dotPath);
-            existingBubble.setAppName(appName);
-            return existingBubble;
-        }
-    }
-
-    private BubbleBarOverflow createOverflow(Context context) {
-        Bitmap bitmap = createOverflowBitmap(context);
-        LayoutInflater inflater = LayoutInflater.from(context);
-        BubbleView bubbleView = (BubbleView) inflater.inflate(
-                R.layout.bubble_bar_overflow_button, mBarView, false /* attachToRoot */);
-        BubbleBarOverflow overflow = new BubbleBarOverflow(bubbleView);
-        bubbleView.setOverflow(overflow, bitmap);
-        return overflow;
-    }
-
-    private Bitmap createOverflowBitmap(Context context) {
-        Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
-                R.drawable.bubble_ic_overflow_button);
-
-        final TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{
-                        R.attr.materialColorOnPrimaryFixed,
-                        R.attr.materialColorPrimaryFixed
-                });
-        int overflowIconColor = ta.getColor(0, Color.WHITE);
-        int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
-        ta.recycle();
-
-        iconDrawable.setTint(overflowIconColor);
-
-        int inset = context.getResources().getDimensionPixelSize(R.dimen.bubblebar_overflow_inset);
-        Drawable foreground = new InsetDrawable(iconDrawable, inset);
-        Drawable drawable = new AdaptiveIconDrawable(new ColorDrawable(overflowBackgroundColor),
-                foreground);
-
-        return mIconFactory.createBadgedIconBitmap(drawable).icon;
-    }
-
     private void onBubbleBarBoundsChanged() {
         int newTop = mBarView.getRestingTopPositionOnScreen();
         if (newTop != mLastSentBubbleBarTop) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index 9e5ffc9..a6b0860 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -27,6 +27,7 @@
 import android.widget.FrameLayout
 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
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 7d27a90..ffab936 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -124,8 +124,6 @@
 
     private final BubbleBarBackground mBubbleBarBackground;
 
-    private boolean mIsAnimatingNewBubble = false;
-
     /**
      * The current bounds of all the bubble bar. Note that these bounds may not account for
      * translation. The bounds should be retrieved using {@link #getBubbleBarBounds()} which
@@ -418,6 +416,7 @@
         LayoutParams lp = (LayoutParams) getLayoutParams();
         lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
         setLayoutParams(lp); // triggers a relayout
+        updateBubbleAccessibilityStates();
     }
 
     /**
@@ -648,7 +647,9 @@
         }
         setAlphaDuringBubbleDrag(1f);
         setTranslationX(0f);
-        setAlpha(1f);
+        if (getBubbleChildCount() > 0) {
+            setAlpha(1f);
+        }
     }
 
     /**
@@ -660,13 +661,25 @@
         return displayHeight - bubbleBarHeight + (int) mController.getBubbleBarTranslationY();
     }
 
-    /**
-     * Updates the bounds with translation that may have been applied and returns the result.
-     */
+    /** Returns the bounds with translation that may have been applied. */
     public Rect getBubbleBarBounds() {
-        mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize;
-        mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
-        return mBubbleBarBounds;
+        Rect bounds = new Rect(mBubbleBarBounds);
+        bounds.top = getTop() + (int) getTranslationY() + mPointerSize;
+        bounds.bottom = getBottom() + (int) getTranslationY();
+        return bounds;
+    }
+
+    /** Returns the expanded bounds with translation that may have been applied. */
+    public Rect getBubbleBarExpandedBounds() {
+        Rect expandedBounds = getBubbleBarBounds();
+        if (!isExpanded() || isExpanding()) {
+            if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+                expandedBounds.right = expandedBounds.left + (int) expandedWidth();
+            } else {
+                expandedBounds.left = expandedBounds.right - (int) expandedWidth();
+            }
+        }
+        return expandedBounds;
     }
 
     /**
@@ -701,25 +714,17 @@
         return mRelativePivotY;
     }
 
-    /** Notifies the bubble bar that a new bubble animation is starting. */
-    public void onAnimatingBubbleStarted() {
-        mIsAnimatingNewBubble = true;
-    }
-
-    /** Notifies the bubble bar that a new bubble animation is complete. */
-    public void onAnimatingBubbleCompleted() {
-        mIsAnimatingNewBubble = false;
-    }
-
     /** Add a new bubble to the bubble bar. */
     public void addBubble(BubbleView bubble) {
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
                 Gravity.LEFT);
+        final int index = bubble.isOverflow() ? getChildCount() : 0;
+
         if (isExpanded()) {
             // if we're expanded scale the new bubble in
             bubble.setScaleX(0f);
             bubble.setScaleY(0f);
-            addView(bubble, 0, lp);
+            addView(bubble, index, lp);
             bubble.showDotIfNeeded(/* animate= */ false);
 
             mBubbleAnimator = new BubbleAnimator(mIconSize, mExpandedBarIconsSpacing,
@@ -748,23 +753,34 @@
             };
             mBubbleAnimator.animateNewBubble(indexOfChild(mSelectedBubbleView), listener);
         } else {
-            addView(bubble, 0, lp);
+            addView(bubble, index, lp);
         }
     }
 
     /** Add a new bubble and remove an old bubble from the bubble bar. */
-    public void addBubbleAndRemoveBubble(View addedBubble, View removedBubble) {
+    public void addBubbleAndRemoveBubble(BubbleView addedBubble, BubbleView removedBubble,
+            Runnable onEndRunnable) {
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
                 Gravity.LEFT);
+        boolean isOverflowSelected = mSelectedBubbleView.isOverflow();
+        boolean removingOverflow = removedBubble.isOverflow();
+        boolean addingOverflow = addedBubble.isOverflow();
+
         if (!isExpanded()) {
             removeView(removedBubble);
-            addView(addedBubble, 0, lp);
+            int index = addingOverflow ? getChildCount() : 0;
+            addView(addedBubble, index, lp);
             return;
         }
+        int index = addingOverflow ? getChildCount() : 0;
         addedBubble.setScaleX(0f);
         addedBubble.setScaleY(0f);
-        addView(addedBubble, 0, lp);
+        addView(addedBubble, index, lp);
 
+        if (isOverflowSelected && removingOverflow) {
+            // The added bubble will be selected
+            mSelectedBubbleView = addedBubble;
+        }
         int indexOfSelectedBubble = indexOfChild(mSelectedBubbleView);
         int indexOfBubbleToRemove = indexOfChild(removedBubble);
 
@@ -777,6 +793,9 @@
                 removeView(removedBubble);
                 updateWidth();
                 mBubbleAnimator = null;
+                if (onEndRunnable != null) {
+                    onEndRunnable.run();
+                }
             }
 
             @Override
@@ -875,6 +894,33 @@
         updateNotificationDotsIfCollapsed();
     }
 
+    /**
+     * Return child views in the order which they are shown on the screen.
+     * <p>
+     * Child views (bubbles) are always ordered based on recency. The most recent bubble is at index
+     * 0.
+     * For example if the child views are (1)(2)(3) then (1) is the most recent bubble and at index
+     * 0.<br>
+     *
+     * How bubbles show up on the screen depends on the bubble bar location. If the bar is on the
+     * left, the most recent bubble is shown on the right. The bubbles from the example above would
+     * be shown as: (3)(2)(1).<br>
+     *
+     * If bubble bar is on the right, then the most recent bubble is on the left. Bubbles from the
+     * example above would be shown as: (1)(2)(3).
+     */
+    private List<View> getChildViewsInOnScreenOrder() {
+        List<View> childViews = new ArrayList<>(getChildCount());
+        for (int i = 0; i < getChildCount(); i++) {
+            childViews.add(getChildAt(i));
+        }
+        if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+            // Visually child views are shown in reverse order when bar is on the left
+            return childViews.reversed();
+        }
+        return childViews;
+    }
+
     private void updateNotificationDotsIfCollapsed() {
         if (isExpanded()) {
             return;
@@ -924,7 +970,7 @@
         final float currentWidth = getWidth();
         final float expandedWidth = expandedWidth();
         final float collapsedWidth = collapsedWidth();
-        int bubbleCount = getChildCount();
+        int childCount = getChildCount();
         float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
         float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
         // When translating X & Y the scale is ignored, so need to deduct it from the translations
@@ -932,7 +978,7 @@
         final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
         // elevation state is opposite to widthState - when expanded all icons are flat
         float elevationState = (1 - widthState);
-        for (int i = 0; i < bubbleCount; i++) {
+        for (int i = 0; i < childCount; i++) {
             BubbleView bv = (BubbleView) getChildAt(i);
             if (bv == mDraggedBubbleView || bv == mDismissedByDragBubbleView) {
                 // Skip the dragged bubble. Its translation is managed by the drag controller.
@@ -951,9 +997,9 @@
             bv.setTranslationY(ty);
 
             // the position of the bubble when the bar is fully expanded
-            final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
+            final float expandedX = getExpandedBubbleTranslationX(i, childCount, onLeft);
             // the position of the bubble when the bar is fully collapsed
-            final float collapsedX = getCollapsedBubbleTranslationX(i, bubbleCount, onLeft);
+            final float collapsedX = getCollapsedBubbleTranslationX(i, childCount, onLeft);
 
             // slowly animate elevation while keeping correct Z ordering
             float fullElevationForChild = (MAX_BUBBLES * mBubbleElevation) - i;
@@ -981,13 +1027,10 @@
                 final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
                 final float targetX = collapsedX + collapsedBarShift;
                 bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
-                // If we're fully collapsed, hide all bubbles except for the first 2. If there are
-                // only 2 bubbles, hide the second bubble as well because it's the overflow.
+                // If we're fully collapsed, hide all bubbles except for the first 2, excluding
+                // the overflow.
                 if (widthState == 0) {
-                    if (i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
-                        bv.setAlpha(0);
-                    } else if (i == MAX_VISIBLE_BUBBLES_COLLAPSED - 1
-                            && bubbleCount == MAX_VISIBLE_BUBBLES_COLLAPSED) {
+                    if (bv.isOverflow() || i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
                         bv.setAlpha(0);
                     } else {
                         bv.setAlpha(1);
@@ -1043,22 +1086,26 @@
         return translationX - getScaleIconShift();
     }
 
-    private float getCollapsedBubbleTranslationX(int bubbleIndex, int bubbleCount, boolean onLeft) {
-        if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+    private float getCollapsedBubbleTranslationX(int bubbleIndex, int childCount, boolean onLeft) {
+        if (bubbleIndex < 0 || bubbleIndex >= childCount) {
             return 0;
         }
         float translationX;
         if (onLeft) {
-            // Shift the first bubble only if there are more bubbles in addition to overflow
-            translationX = mBubbleBarPadding + (
-                    bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
-                            ? mIconOverlapAmount : 0);
+            // Shift the first bubble only if there are more bubbles
+            if (bubbleIndex == 0 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) {
+                translationX = mIconOverlapAmount;
+            } else {
+                translationX = 0f;
+            }
         } else {
-            translationX = mBubbleBarPadding + (
-                    bubbleIndex == 0 || bubbleCount <= MAX_VISIBLE_BUBBLES_COLLAPSED
-                            ? 0 : mIconOverlapAmount);
+            if (bubbleIndex == 1 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) {
+                translationX = mIconOverlapAmount;
+            } else {
+                translationX = 0f;
+            }
         }
-        return translationX - getScaleIconShift();
+        return mBubbleBarPadding + translationX - getScaleIconShift();
     }
 
     /**
@@ -1239,6 +1286,13 @@
     }
 
     /**
+     * Returns whether the bubble bar is expanding.
+     */
+    public boolean isExpanding() {
+        return mWidthAnimator.isRunning() && mIsBarExpanded;
+    }
+
+    /**
      * Get width of the bubble bar as if it would be expanded.
      *
      * @return width of the bubble bar in its expanded state, regardless of current width
@@ -1256,15 +1310,20 @@
     }
 
     private float collapsedWidth() {
-        final int childCount = getChildCount();
+        final int bubbleChildCount = getBubbleChildCount();
         final float horizontalPadding = 2 * mBubbleBarPadding;
-        // If there are more than 2 bubbles, the first 2 should be visible when collapsed.
-        // Otherwise just the first bubble should be visible because we don't show the overflow.
-        return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
+        // If there are more than 2 bubbles, the first 2 should be visible when collapsed,
+        // excluding the overflow.
+        return bubbleChildCount >= MAX_VISIBLE_BUBBLES_COLLAPSED
                 ? getScaledIconSize() + mIconOverlapAmount + horizontalPadding
                 : getScaledIconSize() + horizontalPadding;
     }
 
+    /** Returns the child count excluding the overflow if it's present. */
+    private int getBubbleChildCount() {
+        return hasOverflow() ? getChildCount() - 1 : getChildCount();
+    }
+
     private float getBubbleBarExpandedHeight() {
         return getBubbleBarCollapsedHeight() + mPointerSize;
     }
@@ -1288,9 +1347,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (mIsAnimatingNewBubble) {
-            mController.onBubbleBarTouchedWhileAnimating();
-        }
+        mController.onBubbleBarTouched();
         if (!mIsBarExpanded) {
             // When the bar is collapsed, all taps on it should expand it.
             return true;
@@ -1298,13 +1355,8 @@
         return super.onInterceptTouchEvent(ev);
     }
 
-    /** Whether a new bubble is currently animating. */
-    public boolean isAnimatingNewBubble() {
-        return mIsAnimatingNewBubble;
-    }
-
-    private boolean hasOverview() {
-        // Overview is always the last bubble
+    private boolean hasOverflow() {
+        // Overflow is always the last bubble
         View lastChild = getChildAt(getChildCount() - 1);
         if (lastChild instanceof BubbleView bubbleView) {
             return bubbleView.getBubble() instanceof BubbleBarOverflow;
@@ -1313,21 +1365,39 @@
     }
 
     private void updateBubbleAccessibilityStates() {
-        final int childA11y;
         if (mIsBarExpanded) {
             // Bar is expanded, focus on the bubbles
             setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-            childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
+            // Set up a11y navigation order. Get list of child views in the order they are shown
+            // on screen. And use that to set up navigation so that swiping left focuses the view
+            // on the left and swiping right focuses view on the right.
+            View prevChild = null;
+            for (View childView : getChildViewsInOnScreenOrder()) {
+                childView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                childView.setFocusable(true);
+                final View finalPrevChild = prevChild;
+                // Always need to set a new delegate to clear out any previous.
+                childView.setAccessibilityDelegate(new AccessibilityDelegate() {
+                    @Override
+                    public void onInitializeAccessibilityNodeInfo(View host,
+                            AccessibilityNodeInfo info) {
+                        super.onInitializeAccessibilityNodeInfo(host, info);
+                        if (finalPrevChild != null) {
+                            info.setTraversalAfter(finalPrevChild);
+                        }
+                    }
+                });
+                prevChild = childView;
+            }
         } else {
             // Bar is collapsed, only focus on the bar
             setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-            childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_NO;
-        }
-        for (int i = 0; i < getChildCount(); i++) {
-            getChildAt(i).setImportantForAccessibility(childA11y);
-            // Only allowing focusing on bubbles when bar is expanded. Otherwise, in talkback mode,
-            // bubbles can be navigates to in collapsed mode.
-            getChildAt(i).setFocusable(mIsBarExpanded);
+            for (int i = 0; i < getChildCount(); i++) {
+                View childView = getChildAt(i);
+                childView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+                childView.setFocusable(false);
+            }
         }
     }
 
@@ -1336,7 +1406,7 @@
         CharSequence contentDesc = firstChild != null ? firstChild.getContentDescription() : "";
 
         // Don't count overflow if it exists
-        int bubbleCount = getChildCount() - (hasOverview() ? 1 : 0);
+        int bubbleCount = getChildCount() - (hasOverflow() ? 1 : 0);
         if (bubbleCount > 1) {
             contentDesc = getResources().getString(R.string.bubble_bar_description_multiple_bubbles,
                     contentDesc, bubbleCount - 1);
@@ -1417,7 +1487,6 @@
             pw.println("    bubble key: " + key);
         }
         pw.println("  isExpanded: " + isExpanded());
-        pw.println("  mIsAnimatingNewBubble: " + mIsAnimatingNewBubble);
         if (mBubbleAnimator != null) {
             pw.println("  mBubbleAnimator.isRunning(): " + mBubbleAnimator.isRunning());
             pw.println("  mBubbleAnimator is null");
@@ -1442,8 +1511,8 @@
         /** Returns the translation Y that the bubble bar should have. */
         float getBubbleBarTranslationY();
 
-        /** Notifies the controller that the bubble bar was touched while it was animating. */
-        void onBubbleBarTouchedWhileAnimating();
+        /** Notifies the controller that the bubble bar was touched. */
+        void onBubbleBarTouched();
 
         /** Requests the controller to expand bubble bar */
         void expandBubbleBar();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 9270f68..4fe4ace 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.taskbar.TaskbarInsetsController;
 import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.SystemUiProxy;
@@ -71,9 +72,11 @@
     private BubbleDragController mBubbleDragController;
     private TaskbarStashController mTaskbarStashController;
     private TaskbarInsetsController mTaskbarInsetsController;
+    private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
     private View.OnClickListener mBubbleClickListener;
     private View.OnClickListener mBubbleBarClickListener;
     private BubbleView.Controller mBubbleViewController;
+    private BubbleBarOverflow mOverflowBubble;
 
     // These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
     private final MultiValueAlpha mBubbleBarAlpha;
@@ -90,9 +93,11 @@
     private boolean mHiddenForNoBubbles = true;
     private boolean mShouldShowEducation;
 
+    public boolean mOverflowAdded;
+
     private BubbleBarViewAnimator mBubbleBarViewAnimator;
 
-    private TimeSource mTimeSource = System::currentTimeMillis;
+    private final TimeSource mTimeSource = System::currentTimeMillis;
 
     @Nullable
     private BubbleBarBoundsChangeListener mBoundsChangeListener;
@@ -106,13 +111,16 @@
                 R.dimen.bubblebar_icon_size);
     }
 
-    public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
+    /** Initializes controller. */
+    public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
+            TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
         mBubbleStashController = bubbleControllers.bubbleStashController;
         mBubbleBarController = bubbleControllers.bubbleBarController;
         mBubbleDragController = bubbleControllers.bubbleDragController;
         mTaskbarStashController = controllers.taskbarStashController;
         mTaskbarInsetsController = controllers.taskbarInsetsController;
         mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
+        mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
         onBubbleBarConfigurationChanged(/* animate= */ false);
         mActivity.addOnDeviceProfileChangeListener(
                 dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
@@ -120,6 +128,7 @@
         mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
         mBubbleBarClickListener = v -> expandBubbleBar();
         mBubbleDragController.setupBubbleBarView(mBarView);
+        mOverflowBubble = bubbleControllers.bubbleCreator.createOverflow(mBarView);
         mBarView.setOnClickListener(mBubbleBarClickListener);
         mBarView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
@@ -135,8 +144,8 @@
             }
 
             @Override
-            public void onBubbleBarTouchedWhileAnimating() {
-                BubbleBarViewController.this.onBubbleBarTouchedWhileAnimating();
+            public void onBubbleBarTouched() {
+                BubbleBarViewController.this.onBubbleBarTouched();
             }
 
             @Override
@@ -197,9 +206,12 @@
         }
     }
 
-    private void onBubbleBarTouchedWhileAnimating() {
-        mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
-        mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
+    private void onBubbleBarTouched() {
+        if (isAnimatingNewBubble()) {
+            mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
+            mBubbleStashController.onNewBubbleAnimationInterrupted(false,
+                    mBarView.getTranslationY());
+        }
     }
 
     private void expandBubbleBar() {
@@ -298,7 +310,11 @@
 
     /** Whether a new bubble is animating. */
     public boolean isAnimatingNewBubble() {
-        return mBarView.isAnimatingNewBubble();
+        return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.isAnimating();
+    }
+
+    public boolean isNewBubbleAnimationRunningOrPending() {
+        return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.hasAnimation();
     }
 
     /** The horizontal margin of the bubble bar from the edge of the screen. */
@@ -342,6 +358,7 @@
             if (hidden) {
                 mBarView.setAlpha(0);
                 mBarView.setExpanded(false);
+                updatePersistentTaskbar(/* isBubbleBarExpanded = */ false);
             }
             mActivity.bubbleBarVisibilityChanged(!hidden);
         }
@@ -386,7 +403,8 @@
         int newIconSize;
         int newPadding;
         Resources res = mActivity.getResources();
-        if (mBubbleStashController.isBubblesShowingOnHome()) {
+        if (mBubbleStashController.isBubblesShowingOnHome()
+                || mBubbleStashController.isTransientTaskBar()) {
             newIconSize = getBubbleBarIconSizeFromDeviceProfile(res);
             newPadding = getBubbleBarPaddingFromDeviceProfile(res);
         } else {
@@ -478,8 +496,10 @@
 
     /** Adds a new bubble and removes an old bubble at the same time. */
     public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble,
-            BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation) {
-        mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView());
+            BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation,
+            boolean addOverflowToo) {
+        mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView(),
+                addOverflowToo ? () -> showOverflow(true) : null);
         addedBubble.getView().setOnClickListener(mBubbleClickListener);
         addedBubble.getView().setController(mBubbleViewController);
         removedBubble.getView().setController(null);
@@ -489,6 +509,48 @@
         }
     }
 
+    /** Whether the overflow view is added to the bubble bar. */
+    public boolean isOverflowAdded() {
+        return mOverflowAdded;
+    }
+
+    /** Shows or hides the overflow view. */
+    public void showOverflow(boolean showOverflow) {
+        if (mOverflowAdded == showOverflow) return;
+        mOverflowAdded = showOverflow;
+        if (mOverflowAdded) {
+            mBarView.addBubble(mOverflowBubble.getView());
+            mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
+            mOverflowBubble.getView().setController(mBubbleViewController);
+        } else {
+            mBarView.removeBubble(mOverflowBubble.getView());
+            mOverflowBubble.getView().setOnClickListener(null);
+            mOverflowBubble.getView().setController(null);
+        }
+    }
+
+    /** Adds the overflow view to the bubble bar while animating a view away. */
+    public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble) {
+        if (mOverflowAdded) return;
+        mOverflowAdded = true;
+        mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView(),
+                null /* onEndRunnable */);
+        mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
+        mOverflowBubble.getView().setController(mBubbleViewController);
+        removedBubble.getView().setController(null);
+    }
+
+    /** Removes the overflow view to the bubble bar while animating a view in. */
+    public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble) {
+        if (!mOverflowAdded) return;
+        mOverflowAdded = false;
+        mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView(),
+                null /* onEndRunnable */);
+        addedBubble.getView().setOnClickListener(mBubbleClickListener);
+        addedBubble.getView().setController(mBubbleViewController);
+        mOverflowBubble.getView().setController(null);
+    }
+
     /**
      * Adds the provided bubble to the bubble bar.
      */
@@ -499,15 +561,12 @@
             mBubbleDragController.setupBubbleView(b.getView());
             b.getView().setController(mBubbleViewController);
 
-            if (b instanceof BubbleBarOverflow) {
-                return;
-            }
-
             if (suppressAnimation || !(b instanceof BubbleBarBubble bubble)) {
                 // the bubble bar and handle are initialized as part of the first bubble animation.
                 // if the animation is suppressed, immediately stash or show the bubble bar to
                 // ensure they've been initialized.
-                if (mTaskbarStashController.isInApp()) {
+                if (mTaskbarStashController.isInApp()
+                        && mBubbleStashController.isTransientTaskBar()) {
                     mBubbleStashController.stashBubbleBarImmediate();
                 } else {
                     mBubbleStashController.showBubbleBarImmediate();
@@ -530,15 +589,16 @@
             mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
             return;
         }
-
-        if (mBubbleStashController.isBubblesShowingOnHome() && !isExpanding && !isExpanded()) {
-            mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble);
+        boolean persistentTaskbarOrOnHome = mBubbleStashController.isBubblesShowingOnHome()
+                || !mBubbleStashController.isTransientTaskBar();
+        if (persistentTaskbarOrOnHome && !isExpanded()) {
+            mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble, isExpanding);
             return;
         }
 
-        // only animate the new bubble if we're in an app and not auto expanding
-        if (isInApp && !isExpanding && !isExpanded()) {
-            mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
+        // only animate the new bubble if we're in an app, have handle view and not auto expanding
+        if (isInApp && mBubbleStashController.getHasHandleView() && !isExpanded()) {
+            mBubbleBarViewAnimator.animateBubbleInForStashed(bubble, isExpanding);
         }
     }
 
@@ -567,6 +627,7 @@
     public void setExpanded(boolean isExpanded) {
         if (isExpanded != mBarView.isExpanded()) {
             mBarView.setExpanded(isExpanded);
+            updatePersistentTaskbar(isExpanded);
             if (!isExpanded) {
                 mSystemUiProxy.collapseBubbles();
             } else {
@@ -577,11 +638,34 @@
         }
     }
 
+    private void updatePersistentTaskbar(boolean isBubbleBarExpanded) {
+        if (mBubbleStashController.isTransientTaskBar()) return;
+        boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
+        mTaskbarViewPropertiesProvider
+                .getIconsAlpha()
+                .animateToValue(hideTaskbar ? 0 : 1)
+                .start();
+    }
+
+    /** Return {@code true} if expanded bubble bar would intersect the taskbar. */
+    public boolean isIntersectingTaskbar() {
+        if (mBarView.isExpanding() || mBarView.isExpanded()) {
+            Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds();
+            return mBarView.getBubbleBarExpandedBounds().intersect(taskbarViewBounds);
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Sets whether the bubble bar should be expanded. This method is used in response to UI events
      * from SystemUI.
      */
     public void setExpandedFromSysui(boolean isExpanded) {
+        if (isNewBubbleAnimationRunningOrPending() && isExpanded) {
+            mBubbleBarViewAnimator.expandedWhileAnimating();
+            return;
+        }
         if (!isExpanded) {
             mBubbleStashController.stashBubbleBar();
         } else {
@@ -598,6 +682,7 @@
     /**
      * Updates the dragged bubble view in the bubble bar view, and notifies SystemUI
      * that a bubble is being dragged to dismiss.
+     *
      * @param bubbleView dragged bubble view
      */
     public void onBubbleDragStart(@NonNull BubbleView bubbleView) {
@@ -705,4 +790,14 @@
             pw.println("  Bubble bar view is null!");
         }
     }
+
+    /** Interface for BubbleBarViewController to get the taskbar view properties. */
+    public interface TaskbarViewPropertiesProvider {
+
+        /** Returns the bounds of the taskbar. */
+        Rect getTaskbarViewBounds();
+
+        /** Returns taskbar icons alpha */
+        MultiPropertyFactory<View>.MultiProperty getIconsAlpha();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index 03140fe..e00916a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -15,24 +15,32 @@
  */
 package com.android.launcher3.taskbar.bubbles;
 
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_BUBBLE_BAR;
+
+import android.graphics.Rect;
+import android.view.View;
+
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.RunnableList;
 
 import java.io.PrintWriter;
+import java.util.Optional;
 
-/**
- * Hosts various bubble controllers to facilitate passing between one another.
- */
+/** Hosts various bubble controllers to facilitate passing between one another. */
 public class BubbleControllers {
 
     public final BubbleBarController bubbleBarController;
     public final BubbleBarViewController bubbleBarViewController;
     public final BubbleStashController bubbleStashController;
-    public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
+    public final Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController;
     public final BubbleDragController bubbleDragController;
     public final BubbleDismissController bubbleDismissController;
     public final BubbleBarPinController bubbleBarPinController;
     public final BubblePinController bubblePinController;
+    public final BubbleCreator bubbleCreator;
 
     private final RunnableList mPostInitRunnables = new RunnableList();
 
@@ -45,11 +53,12 @@
             BubbleBarController bubbleBarController,
             BubbleBarViewController bubbleBarViewController,
             BubbleStashController bubbleStashController,
-            BubbleStashedHandleViewController bubbleStashedHandleViewController,
+            Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController,
             BubbleDragController bubbleDragController,
             BubbleDismissController bubbleDismissController,
             BubbleBarPinController bubbleBarPinController,
-            BubblePinController bubblePinController) {
+            BubblePinController bubblePinController,
+            BubbleCreator bubbleCreator) {
         this.bubbleBarController = bubbleBarController;
         this.bubbleBarViewController = bubbleBarViewController;
         this.bubbleStashController = bubbleStashController;
@@ -58,6 +67,7 @@
         this.bubbleDismissController = bubbleDismissController;
         this.bubbleBarPinController = bubbleBarPinController;
         this.bubblePinController = bubblePinController;
+        this.bubbleCreator = bubbleCreator;
     }
 
     /**
@@ -68,9 +78,28 @@
     public void init(TaskbarControllers taskbarControllers) {
         bubbleBarController.init(this,
                 taskbarControllers.navbarButtonsViewController::isImeVisible);
-        bubbleBarViewController.init(taskbarControllers, this);
-        bubbleStashedHandleViewController.init(taskbarControllers, this);
-        bubbleStashController.init(taskbarControllers, this);
+        bubbleStashedHandleViewController.ifPresent(
+                controller -> controller.init(/* bubbleControllers = */ this));
+        bubbleStashController.init(
+                taskbarControllers.taskbarInsetsController,
+                bubbleBarViewController,
+                bubbleStashedHandleViewController.orElse(null),
+                taskbarControllers::runAfterInit
+        );
+        bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this,
+                new TaskbarViewPropertiesProvider() {
+                    @Override
+                    public Rect getTaskbarViewBounds() {
+                        return taskbarControllers.taskbarViewController.getIconLayoutBounds();
+                    }
+
+                    @Override
+                    public MultiPropertyFactory<View>.MultiProperty getIconsAlpha() {
+                        return taskbarControllers.taskbarViewController
+                                .getTaskbarIconAlpha()
+                                .get(ALPHA_INDEX_BUBBLE_BAR);
+                    }
+                });
         bubbleDragController.init(/* bubbleControllers = */ this);
         bubbleDismissController.init(/* bubbleControllers = */ this);
         bubbleBarPinController.init(this);
@@ -93,7 +122,7 @@
      * Cleans up all controllers.
      */
     public void onDestroy() {
-        bubbleStashedHandleViewController.onDestroy();
+        bubbleStashedHandleViewController.ifPresent(BubbleStashedHandleViewController::onDestroy);
         bubbleBarController.onDestroy();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
new file mode 100644
index 0000000..8e9a2f6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -0,0 +1,221 @@
+/*
+ * 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 static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_PERSONS_DATA;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
+
+import static com.android.launcher3.icons.FastBitmapDrawable.WHITE_SCRIM_ALPHA;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.PathParser;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.appcompat.content.res.AppCompatResources;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.launcher3.R;
+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;
+
+/**
+ * Loads the necessary info to populate / present a bubble (name, icon, shortcut).
+ */
+public class BubbleCreator {
+
+    private static final String TAG = BubbleCreator.class.getSimpleName();
+
+    private final Context mContext;
+    private final LauncherApps mLauncherApps;
+    private final BubbleIconFactory mIconFactory;
+
+    public BubbleCreator(Context context) {
+        mContext = context;
+        mLauncherApps = mContext.getSystemService(LauncherApps.class);
+        mIconFactory = new BubbleIconFactory(context,
+                context.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size),
+                context.getResources().getDimensionPixelSize(R.dimen.bubblebar_badge_size),
+                context.getResources().getColor(R.color.important_conversation),
+                context.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.importance_ring_stroke_width));
+    }
+
+    /**
+     * Creates a BubbleBarBubble object, including the view if needed, and populates it with
+     * the info needed for presentation.
+     *
+     * @param context the context to use for inflation.
+     * @param info the info to use to populate the bubble.
+     * @param barView the parent view for the bubble (bubble is not added to the view).
+     * @param existingBubble if a bubble exists already, this object gets updated with the new
+     *                       info & returned (& any existing views are reused instead of inflating
+     *                       new ones.
+     */
+    @Nullable
+    public BubbleBarBubble populateBubble(Context context, BubbleInfo info, ViewGroup barView,
+            @Nullable BubbleBarBubble existingBubble) {
+        String appName;
+        Bitmap badgeBitmap;
+        Bitmap bubbleBitmap;
+        Path dotPath;
+        int dotColor;
+
+        boolean isImportantConvo = info.isImportantConversation();
+
+        ShortcutRequest.QueryResult result = new ShortcutRequest(context,
+                new UserHandle(info.getUserId()))
+                .forPackage(info.getPackageName(), info.getShortcutId())
+                .query(FLAG_MATCH_DYNAMIC
+                        | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+                        | FLAG_MATCH_CACHED
+                        | FLAG_GET_PERSONS_DATA);
+
+        ShortcutInfo shortcutInfo = result.size() > 0 ? result.get(0) : null;
+        if (shortcutInfo == null) {
+            Log.w(TAG, "No shortcutInfo found for bubble: " + info.getKey()
+                    + " with shortcutId: " + info.getShortcutId());
+        }
+
+        ApplicationInfo appInfo;
+        try {
+            appInfo = mLauncherApps.getApplicationInfo(
+                    info.getPackageName(),
+                    0,
+                    new UserHandle(info.getUserId()));
+        } catch (PackageManager.NameNotFoundException e) {
+            // If we can't find package... don't think we should show the bubble.
+            Log.w(TAG, "Unable to find packageName: " + info.getPackageName());
+            return null;
+        }
+        if (appInfo == null) {
+            Log.w(TAG, "Unable to find appInfo: " + info.getPackageName());
+            return null;
+        }
+        PackageManager pm = context.getPackageManager();
+        appName = String.valueOf(appInfo.loadLabel(pm));
+        Drawable appIcon = appInfo.loadUnbadgedIcon(pm);
+        Drawable badgedIcon = pm.getUserBadgedIcon(appIcon, new UserHandle(info.getUserId()));
+
+        // Badged bubble image
+        Drawable bubbleDrawable = mIconFactory.getBubbleDrawable(context, shortcutInfo,
+                info.getIcon());
+        if (bubbleDrawable == null) {
+            // Default to app icon
+            bubbleDrawable = appIcon;
+        }
+
+        BitmapInfo badgeBitmapInfo = mIconFactory.getBadgeBitmap(badgedIcon, isImportantConvo);
+        badgeBitmap = badgeBitmapInfo.icon;
+
+        float[] bubbleBitmapScale = new float[1];
+        bubbleBitmap = mIconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
+
+        // Dot color & placement
+        Path iconPath = PathParser.createPathFromPathData(
+                context.getResources().getString(
+                        com.android.internal.R.string.config_icon_mask));
+        Matrix matrix = new Matrix();
+        float scale = bubbleBitmapScale[0];
+        float radius = BubbleView.DEFAULT_PATH_SIZE / 2f;
+        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+                radius /* pivot y */);
+        iconPath.transform(matrix);
+        dotPath = iconPath;
+        dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
+                Color.WHITE, WHITE_SCRIM_ALPHA / 255f);
+
+        if (existingBubble == null) {
+            LayoutInflater inflater = LayoutInflater.from(context);
+            BubbleView bubbleView = (BubbleView) inflater.inflate(
+                    R.layout.bubblebar_item_view, barView, false /* attachToRoot */);
+
+            BubbleBarBubble bubble = new BubbleBarBubble(info, bubbleView,
+                    badgeBitmap, bubbleBitmap, dotColor, dotPath, appName);
+            bubbleView.setBubble(bubble);
+            return bubble;
+        } else {
+            // If we already have a bubble (so it already has an inflated view), update it.
+            existingBubble.setInfo(info);
+            existingBubble.setBadge(badgeBitmap);
+            existingBubble.setIcon(bubbleBitmap);
+            existingBubble.setDotColor(dotColor);
+            existingBubble.setDotPath(dotPath);
+            existingBubble.setAppName(appName);
+            return existingBubble;
+        }
+    }
+
+    /**
+     * Creates the overflow view shown in the bubble bar.
+     *
+     * @param barView the parent view for the bubble (bubble is not added to the view).
+     */
+    public BubbleBarOverflow createOverflow(ViewGroup barView) {
+        Bitmap bitmap = createOverflowBitmap();
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        BubbleView bubbleView = (BubbleView) inflater.inflate(
+                R.layout.bubble_bar_overflow_button, barView, false /* attachToRoot */);
+        BubbleBarOverflow overflow = new BubbleBarOverflow(bubbleView);
+        bubbleView.setOverflow(overflow, bitmap);
+        return overflow;
+    }
+
+    private Bitmap createOverflowBitmap() {
+        Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
+                R.drawable.bubble_ic_overflow_button);
+
+        final TypedArray ta = mContext.obtainStyledAttributes(
+                new int[]{
+                        R.attr.materialColorOnPrimaryFixed,
+                        R.attr.materialColorPrimaryFixed
+                });
+        int overflowIconColor = ta.getColor(0, Color.WHITE);
+        int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
+        ta.recycle();
+
+        iconDrawable.setTint(overflowIconColor);
+
+        int inset = mContext.getResources().getDimensionPixelSize(R.dimen.bubblebar_overflow_inset);
+        Drawable foreground = new InsetDrawable(iconDrawable, inset);
+        Drawable drawable = new AdaptiveIconDrawable(new ColorDrawable(overflowBackgroundColor),
+                foreground);
+
+        return mIconFactory.createBadgedIconBitmap(drawable).icon;
+    }
+
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 7aed2d2..87f466f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -128,7 +128,7 @@
                         boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
                         boolean allRelevantPropertyAnimationsEnded) -> {
                     if (canceled || allRelevantPropertyAnimationsEnded) {
-                        resetAnimatedViews(restingPosition);
+                        resetAnimatedViews(restingPosition, /* dismissed= */ false);
                         if (endActions != null) {
                             endActions.run();
                         }
@@ -197,7 +197,7 @@
                         boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
                         boolean allRelevantPropertyAnimationsEnded) -> {
                     if (canceled || allRelevantPropertyAnimationsEnded) {
-                        resetAnimatedViews(initialPosition);
+                        resetAnimatedViews(initialPosition, /* dismissed= */ true);
                         if (endActions != null) endActions.run();
                     }
                 })
@@ -208,11 +208,14 @@
      * Reset the animated views to the initial state
      *
      * @param initialPosition position of the bubble
+     * @param dismissed whether the animated view was dismissed
      */
-    private void resetAnimatedViews(@NonNull PointF initialPosition) {
+    private void resetAnimatedViews(@NonNull PointF initialPosition, boolean dismissed) {
         mView.setScaleX(1f);
         mView.setScaleY(1f);
-        mView.setAlpha(1f);
+        if (!dismissed) {
+            mView.setAlpha(1f);
+        }
         mView.setTranslationX(initialPosition.x);
         mView.setTranslationY(initialPosition.y);
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
index a77e685..1341b53 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -27,6 +27,7 @@
 import android.widget.FrameLayout
 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
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
deleted file mode 100644
index 74f58ac..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar.bubbles;
-
-import static java.lang.Math.abs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.annotation.Nullable;
-import android.view.InsetsController;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
-import com.android.launcher3.taskbar.StashedHandleViewController;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.launcher3.taskbar.TaskbarInsetsController;
-import com.android.launcher3.taskbar.TaskbarStashController;
-import com.android.launcher3.util.MultiPropertyFactory;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.shared.animation.PhysicsAnimator;
-
-import java.io.PrintWriter;
-
-/**
- * Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
- * create a cohesive animation between stashed/unstashed states.
- */
-public class BubbleStashController {
-
-    private static final String TAG = "BubbleStashController";
-
-    /**
-     * How long to stash/unstash.
-     */
-    public static final long BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
-
-    /**
-     * The scale bubble bar animates to when being stashed.
-     */
-    private static final float STASHED_BAR_SCALE = 0.5f;
-
-    protected final TaskbarActivityContext mActivity;
-
-    // Initialized in init.
-    private TaskbarControllers mControllers;
-    private TaskbarInsetsController mTaskbarInsetsController;
-    private BubbleBarViewController mBarViewController;
-    private BubbleStashedHandleViewController mHandleViewController;
-    private TaskbarStashController mTaskbarStashController;
-
-    private MultiPropertyFactory.MultiProperty mIconAlphaForStash;
-    private AnimatedFloat mIconScaleForStash;
-    private AnimatedFloat mIconTranslationYForStash;
-    private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
-
-    private boolean mRequestedStashState;
-    private boolean mRequestedExpandedState;
-
-    private boolean mIsStashed;
-    private int mStashedHeight;
-    private int mUnstashedHeight;
-    private boolean mBubblesShowingOnHome;
-    private boolean mBubblesShowingOnOverview;
-    private boolean mIsSysuiLocked;
-
-    private final float mHandleCenterFromScreenBottom;
-
-    @Nullable
-    private AnimatorSet mAnimator;
-
-    public BubbleStashController(TaskbarActivityContext activity) {
-        mActivity = activity;
-        // the handle is centered within the stashed taskbar area
-        mHandleCenterFromScreenBottom =
-                mActivity.getResources().getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f;
-    }
-
-    public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
-        mControllers = controllers;
-        mTaskbarInsetsController = controllers.taskbarInsetsController;
-        mBarViewController = bubbleControllers.bubbleBarViewController;
-        mHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
-        mTaskbarStashController = controllers.taskbarStashController;
-
-        mIconAlphaForStash = mBarViewController.getBubbleBarAlpha().get(0);
-        mIconScaleForStash = mBarViewController.getBubbleBarScale();
-        mIconTranslationYForStash = mBarViewController.getBubbleBarTranslationY();
-
-        mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
-                StashedHandleViewController.ALPHA_INDEX_STASHED);
-
-        mStashedHeight = mHandleViewController.getStashedHeight();
-        mUnstashedHeight = mHandleViewController.getUnstashedHeight();
-    }
-
-    /**
-     * Returns the touchable height of the bubble bar based on it's stashed state.
-     */
-    public int getTouchableHeight() {
-        return mIsStashed ? mStashedHeight : mUnstashedHeight;
-    }
-
-    /**
-     * Returns whether the bubble bar is currently stashed.
-     */
-    public boolean isStashed() {
-        return mIsStashed;
-    }
-
-    /**
-     * Animates the handle (or bubble bar depending on state) to be visible after the device is
-     * unlocked.
-     *
-     * <p>Normally either the bubble bar or the handle is visible,
-     * and {@link #showBubbleBar(boolean)} and {@link #stashBubbleBar()} are used to transition
-     * between these two states. But the transition from the state where both the bar and handle
-     * are invisible is slightly different.
-     */
-    private void animateAfterUnlock() {
-        AnimatorSet animatorSet = new AnimatorSet();
-        if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
-            mIsStashed = false;
-            animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
-                    mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
-                    mIconAlphaForStash.animateToValue(1));
-        } else {
-            mIsStashed = true;
-            animatorSet.playTogether(mBubbleStashedHandleAlpha.animateToValue(1));
-        }
-
-        animatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                onIsStashedChanged();
-            }
-        });
-        animatorSet.setDuration(BAR_STASH_DURATION).start();
-    }
-
-    /**
-     * Called when launcher enters or exits the home page. Bubbles are unstashed on home.
-     */
-    public void setBubblesShowingOnHome(boolean onHome) {
-        if (mBubblesShowingOnHome != onHome) {
-            mBubblesShowingOnHome = onHome;
-
-            if (!mBarViewController.hasBubbles()) {
-                // if there are no bubbles, there's nothing to show, so just return.
-                return;
-            }
-
-            if (mBubblesShowingOnHome) {
-                showBubbleBar(/* expanded= */ false);
-                // When transitioning from app to home the stash animator may already have been
-                // created, so we need to animate the bubble bar here to align with hotseat.
-                if (!mIsStashed) {
-                    mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForHotseat())
-                            .start();
-                }
-                // If the bubble bar is already unstashed, the taskbar touchable region won't be
-                // updated correctly, so force an update here.
-                mControllers.runAfterInit(() ->
-                        mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
-            } else if (!mBarViewController.isExpanded()) {
-                stashBubbleBar();
-            }
-        }
-    }
-
-    /** Whether bubbles are showing on the launcher home page. */
-    public boolean isBubblesShowingOnHome() {
-        boolean hasBubbles = mBarViewController != null && mBarViewController.hasBubbles();
-        return mBubblesShowingOnHome && hasBubbles;
-    }
-
-    // TODO: when tapping on an app in overview, this is a bit delayed compared to taskbar stashing
-    /** Called when launcher enters or exits overview. Bubbles are unstashed on overview. */
-    public void setBubblesShowingOnOverview(boolean onOverview) {
-        if (mBubblesShowingOnOverview != onOverview) {
-            mBubblesShowingOnOverview = onOverview;
-            if (!mBubblesShowingOnOverview && !mBarViewController.isExpanded()) {
-                stashBubbleBar();
-            } else {
-                // When transitioning to overview the stash animator may already have been
-                // created, so we need to animate the bubble bar here to align with taskbar.
-                mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForTaskbar())
-                        .start();
-            }
-        }
-    }
-
-    /** Whether bubbles are showing on Overview. */
-    public boolean isBubblesShowingOnOverview() {
-        return mBubblesShowingOnOverview;
-    }
-
-    /** Called when sysui locked state changes, when locked, bubble bar is stashed. */
-    public void onSysuiLockedStateChange(boolean isSysuiLocked) {
-        if (isSysuiLocked != mIsSysuiLocked) {
-            mIsSysuiLocked = isSysuiLocked;
-            if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
-                animateAfterUnlock();
-            }
-        }
-    }
-
-    /**
-     * Stashes the bubble bar if allowed based on other state (e.g. on home and overview the
-     * bar does not stash).
-     */
-    public void stashBubbleBar() {
-        mRequestedStashState = true;
-        mRequestedExpandedState = false;
-        updateStashedAndExpandedState();
-    }
-
-    /**
-     * Shows the bubble bar, and expands bubbles depending on {@param expandBubbles}.
-     */
-    public void showBubbleBar(boolean expandBubbles) {
-        mRequestedStashState = false;
-        mRequestedExpandedState = expandBubbles;
-        updateStashedAndExpandedState();
-    }
-
-    private void updateStashedAndExpandedState() {
-        if (mBarViewController.isHiddenForNoBubbles()) {
-            // If there are no bubbles the bar and handle are invisible, nothing to do here.
-            return;
-        }
-        boolean isStashed = mRequestedStashState
-                && !mBubblesShowingOnHome
-                && !mBubblesShowingOnOverview;
-        if (mIsStashed != isStashed) {
-            // notify the view controller that the stash state is about to change so that it can
-            // cancel an ongoing animation if there is one.
-            // note that this has to be called before updating mIsStashed with the new value,
-            // otherwise interrupting an ongoing animation may update it again with the wrong state
-            mBarViewController.onStashStateChanging();
-            mIsStashed = isStashed;
-            if (mAnimator != null) {
-                mAnimator.cancel();
-            }
-            mAnimator = createStashAnimator(mIsStashed, BAR_STASH_DURATION);
-            mAnimator.start();
-            onIsStashedChanged();
-        }
-        if (mBarViewController.isExpanded() != mRequestedExpandedState) {
-            mBarViewController.setExpanded(mRequestedExpandedState);
-        }
-    }
-
-    /**
-     * Create a stash animation.
-     *
-     * @param isStashed whether it's a stash animation or an unstash animation
-     * @param duration duration of the animation
-     * @return the animation
-     */
-    private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
-        AnimatorSet animatorSet = new AnimatorSet();
-
-        AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
-        // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
-        AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
-        AnimatorSet secondHalfAnimatorSet = new AnimatorSet();
-
-        final float firstHalfDurationScale;
-        final float secondHalfDurationScale;
-
-        if (isStashed) {
-            firstHalfDurationScale = 0.75f;
-            secondHalfDurationScale = 0.5f;
-
-            fullLengthAnimatorSet.play(
-                    mIconTranslationYForStash.animateToValue(getStashTranslation()));
-
-            firstHalfAnimatorSet.playTogether(
-                    mIconAlphaForStash.animateToValue(0),
-                    mIconScaleForStash.animateToValue(STASHED_BAR_SCALE));
-            secondHalfAnimatorSet.playTogether(
-                    mBubbleStashedHandleAlpha.animateToValue(1));
-        } else  {
-            firstHalfDurationScale = 0.5f;
-            secondHalfDurationScale = 0.75f;
-
-            final float translationY = getBubbleBarTranslationY();
-
-            fullLengthAnimatorSet.playTogether(
-                    mIconScaleForStash.animateToValue(1),
-                    mIconTranslationYForStash.animateToValue(translationY));
-
-            firstHalfAnimatorSet.playTogether(
-                    mBubbleStashedHandleAlpha.animateToValue(0)
-            );
-            secondHalfAnimatorSet.playTogether(
-                    mIconAlphaForStash.animateToValue(1)
-            );
-        }
-
-        fullLengthAnimatorSet.play(mHandleViewController.createRevealAnimToIsStashed(isStashed));
-
-        fullLengthAnimatorSet.setDuration(duration);
-        firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale));
-        secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
-        secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
-
-        animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
-                secondHalfAnimatorSet);
-        animatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimator = null;
-                mControllers.runAfterInit(() -> {
-                    if (isStashed) {
-                        mBarViewController.setExpanded(false);
-                    }
-                    mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
-                });
-            }
-        });
-        return animatorSet;
-    }
-
-    private float getStashTranslation() {
-        return (mUnstashedHeight - mStashedHeight) / 2f;
-    }
-
-    private void onIsStashedChanged() {
-        mControllers.runAfterInit(() -> {
-            mHandleViewController.onIsStashedChanged();
-            mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
-        });
-    }
-
-    public float getBubbleBarTranslationYForTaskbar() {
-        return -mActivity.getDeviceProfile().taskbarBottomMargin;
-    }
-
-    private float getBubbleBarTranslationYForHotseat() {
-        final float hotseatBottomSpace = mActivity.getDeviceProfile().hotseatBarBottomSpacePx;
-        final float hotseatCellHeight = mActivity.getDeviceProfile().hotseatCellHeightPx;
-        return -hotseatBottomSpace - hotseatCellHeight + mUnstashedHeight - abs(
-                hotseatCellHeight - mUnstashedHeight) / 2;
-    }
-
-    public float getBubbleBarTranslationY() {
-        // If we're on home, adjust the translation so the bubble bar aligns with hotseat.
-        // Otherwise we're either showing in an app or in overview. In either case adjust it so
-        // the bubble bar aligns with the taskbar.
-        return mBubblesShowingOnHome ? getBubbleBarTranslationYForHotseat()
-                : getBubbleBarTranslationYForTaskbar();
-    }
-
-    /**
-     * The difference on the Y axis between the center of the handle and the center of the bubble
-     * bar.
-     */
-    public float getDiffBetweenHandleAndBarCenters() {
-        // the difference between the centers of the handle and the bubble bar is the difference
-        // between their distance from the bottom of the screen.
-
-        float barCenter = mBarViewController.getBubbleBarCollapsedHeight() / 2f;
-        return mHandleCenterFromScreenBottom - barCenter;
-    }
-
-    /** The distance the handle moves as part of the new bubble animation. */
-    public float getStashedHandleTranslationForNewBubbleAnimation() {
-        // the should move up to the top of the stashed taskbar area. it is centered within it so
-        // it should move the same distance as it is away from the bottom.
-        return -mHandleCenterFromScreenBottom;
-    }
-
-    /** Checks whether the motion event is over the stash handle. */
-    public boolean isEventOverStashHandle(MotionEvent ev) {
-        return mHandleViewController.isEventOverHandle(ev);
-    }
-
-    /** Set a bubble bar location */
-    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
-        mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
-    }
-
-    /** Returns the [PhysicsAnimator] for the stashed handle view. */
-    public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
-        return mHandleViewController.getPhysicsAnimator();
-    }
-
-    /** Notifies taskbar that it should update its touchable region. */
-    public void updateTaskbarTouchRegion() {
-        mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
-    }
-
-    /** Shows the bubble bar immediately without animation. */
-    public void showBubbleBarImmediate() {
-        mHandleViewController.setTranslationYForSwipe(0);
-        mIconTranslationYForStash.updateValue(getBubbleBarTranslationY());
-        mIconAlphaForStash.setValue(1);
-        mIconScaleForStash.updateValue(1);
-        mIsStashed = false;
-        onIsStashedChanged();
-    }
-
-    /** Stashes the bubble bar immediately without animation. */
-    public void stashBubbleBarImmediate() {
-        mHandleViewController.setTranslationYForSwipe(0);
-        mBubbleStashedHandleAlpha.setValue(1);
-        mIconAlphaForStash.setValue(0);
-        mIconTranslationYForStash.updateValue(getStashTranslation());
-        mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
-        mIsStashed = true;
-        onIsStashedChanged();
-    }
-
-    /**
-     * Updates the values of the internal animators after the new bubble animation was interrupted
-     *
-     * @param isStashed whether the current state should be stashed
-     * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
-     *                              bubble bar is showing to ensure that the stash animator runs
-     *                              smoothly.
-     */
-    public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) {
-        if (isStashed) {
-            mBubbleStashedHandleAlpha.setValue(1);
-            mIconAlphaForStash.setValue(0);
-            mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
-            mIconTranslationYForStash.updateValue(getStashTranslation());
-        } else {
-            mBubbleStashedHandleAlpha.setValue(0);
-            mHandleViewController.setTranslationYForSwipe(0);
-            mIconAlphaForStash.setValue(1);
-            mIconScaleForStash.updateValue(1);
-            mIconTranslationYForStash.updateValue(bubbleBarTranslationY);
-        }
-        mIsStashed = isStashed;
-        onIsStashedChanged();
-    }
-
-    /** Set the translation Y for the stashed handle. */
-    public void setHandleTranslationY(float ty) {
-        mHandleViewController.setTranslationYForSwipe(ty);
-    }
-
-    /** Dumps the state of BubbleStashController. */
-    public void dump(PrintWriter pw) {
-        pw.println("Bubble stash controller state:");
-        pw.println("  mIsStashed: " + mIsStashed);
-        pw.println("  mBubblesShowingOnOverview: " + mBubblesShowingOnOverview);
-        pw.println("  mBubblesShowingOnHome: " + mBubblesShowingOnHome);
-        pw.println("  mIsSysuiLocked: " + mIsSysuiLocked);
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 91103d7..8158fe7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -33,7 +33,7 @@
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.taskbar.StashedHandleView;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -79,7 +79,8 @@
         mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
     }
 
-    public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
+    /** Initialize controller. */
+    public void init(BubbleControllers bubbleControllers) {
         mBarViewController = bubbleControllers.bubbleBarViewController;
         mBubbleStashController = bubbleControllers.bubbleStashController;
 
@@ -117,7 +118,7 @@
                     public Rect getSampledRegion(View sampledView) {
                         return mStashedHandleView.getSampledRegion();
                     }
-                }, Executors.UI_HELPER_EXECUTOR);
+                }, Executors.MAIN_EXECUTOR, Executors.UI_HELPER_EXECUTOR);
 
         mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
                 updateBounds(mBarViewController.getBubbleBarLocation()));
@@ -244,6 +245,11 @@
         mStashedHandleView.setTranslationY(transY);
     }
 
+    /** Returns the translation of the stashed handle. */
+    public float getTranslationY() {
+        return mStashedHandleView.getTranslationY();
+    }
+
     /**
      * Used by {@link BubbleStashController} to animate the handle when stashing or un stashing.
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 739be9e..eb3b24b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -74,6 +74,7 @@
     private boolean mOnLeft = false;
 
     private BubbleBarItem mBubble;
+    private boolean mIsOverflow;
 
     private Bitmap mIcon;
 
@@ -271,12 +272,18 @@
      */
     public void setOverflow(BubbleBarOverflow overflow, Bitmap bitmap) {
         mBubble = overflow;
+        mIsOverflow = true;
         mIcon = bitmap;
         updateBubbleIcon();
         mAppIcon.setVisibility(GONE); // Overflow doesn't show the app badge
         setContentDescription(getResources().getString(R.string.bubble_bar_overflow_description));
     }
 
+    /** Whether this view represents the overflow button. */
+    public boolean isOverflow() {
+        return mIsOverflow;
+    }
+
     /** Returns the bubble being rendered in this view. */
     @Nullable
     public BubbleBarItem getBubble() {
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 feff9fd..2ed88d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -26,8 +26,8 @@
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
-import com.android.launcher3.taskbar.bubbles.BubbleStashController
 import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
 import com.android.wm.shell.shared.animation.PhysicsAnimator
 
 /** Handles animations for bubble bar bubbles. */
@@ -43,6 +43,14 @@
     private val bubbleBarBounceDistanceInPx =
         bubbleBarView.resources.getDimensionPixelSize(R.dimen.bubblebar_bounce_distance)
 
+    fun hasAnimation() = animatingBubble != null
+
+    val isAnimating: Boolean
+        get() {
+            val animatingBubble = animatingBubble ?: return false
+            return animatingBubble.state != AnimatingBubble.State.CREATED
+        }
+
     private companion object {
         /** The time to show the flyout. */
         const val FLYOUT_DELAY_MS: Long = 2500
@@ -58,8 +66,33 @@
     private data class AnimatingBubble(
         val bubbleView: BubbleView,
         val showAnimation: Runnable,
-        val hideAnimation: Runnable
-    )
+        val hideAnimation: Runnable,
+        val expand: Boolean,
+        val state: State = State.CREATED
+    ) {
+
+        /**
+         * The state of the animation.
+         *
+         * The animation is initially created but will be scheduled later using the [Scheduler].
+         *
+         * The normal uninterrupted cycle is for the bubble notification to animate in, then be in a
+         * transient state and eventually to animate out.
+         *
+         * However different events, such as touch and external signals, may cause the animation to
+         * end earlier.
+         */
+        enum class State {
+            /** The animation is created but not started yet. */
+            CREATED,
+            /** The bubble notification is animating in. */
+            ANIMATING_IN,
+            /** The bubble notification is now fully showing and waiting to be hidden. */
+            IN,
+            /** The bubble notification is animating out. */
+            ANIMATING_OUT
+        }
+    }
 
     /** An interface for scheduling jobs. */
     interface Scheduler {
@@ -97,15 +130,18 @@
         )
 
     /** Animates a bubble for the state where the bubble bar is stashed. */
-    fun animateBubbleInForStashed(b: BubbleBarBubble) {
+    fun animateBubbleInForStashed(b: BubbleBarBubble, isExpanding: Boolean) {
+        // TODO b/346400677: handle animations for the same bubble interrupting each other
+        if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
         val bubbleView = b.view
         val animator = PhysicsAnimator.getInstance(bubbleView)
         if (animator.isRunning()) animator.cancel()
         // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
         // and the second part hides it after a delay.
         val showAnimation = buildHandleToBubbleBarAnimation()
-        val hideAnimation = buildBubbleBarToHandleAnimation()
-        animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+        val hideAnimation = if (isExpanding) Runnable {} else buildBubbleBarToHandleAnimation()
+        animatingBubble =
+            AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
         scheduler.post(showAnimation)
         scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
     }
@@ -125,8 +161,8 @@
      *    visible which helps avoiding further updates when we re-enter the second part.
      */
     private fun buildHandleToBubbleBarAnimation() = Runnable {
+        moveToState(AnimatingBubble.State.ANIMATING_IN)
         // prepare the bubble bar for the animation
-        bubbleBarView.onAnimatingBubbleStarted()
         bubbleBarView.visibility = VISIBLE
         bubbleBarView.alpha = 0f
         bubbleBarView.translationY = 0f
@@ -138,26 +174,29 @@
         // handle. when the handle becomes invisible and we start animating in the bubble bar,
         // the translation y is offset by this value to make the transition from the handle to the
         // bar smooth.
-        val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+        val offset = bubbleStashController.getDiffBetweenHandleAndBarCenters()
+        val stashedHandleTranslationYForAnimation =
+            bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
         val stashedHandleTranslationY =
-            bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+            bubbleStashController.getHandleTranslationY() ?: return@Runnable
+        val translationTracker = TranslationTracker(stashedHandleTranslationY)
 
         // this is the total distance that both the stashed handle and the bubble will be traveling
         // at the end of the animation the bubble bar will be positioned in the same place when it
         // shows while we're in an app.
         val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
-        val animator = bubbleStashController.stashedHandlePhysicsAnimator
+        val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
         animator.setDefaultSpringConfig(springConfig)
         animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
         animator.addUpdateListener { handle, values ->
             val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
             when {
-                ty >= stashedHandleTranslationY -> {
+                ty >= stashedHandleTranslationYForAnimation -> {
                     // we're in the first leg of the animation. only animate the handle. the bubble
                     // bar remains hidden during this part of the animation
 
                     // map the path [0, stashedHandleTranslationY] to [0,1]
-                    val fraction = ty / stashedHandleTranslationY
+                    val fraction = ty / stashedHandleTranslationYForAnimation
                     handle.alpha = 1 - fraction
                 }
                 ty >= totalTranslationY -> {
@@ -171,8 +210,8 @@
                     if (bubbleBarView.alpha != 1f) {
                         // map the path [stashedHandleTranslationY, totalTranslationY] to [0, 1]
                         val fraction =
-                            (ty - stashedHandleTranslationY) /
-                                (totalTranslationY - stashedHandleTranslationY)
+                            (ty - stashedHandleTranslationYForAnimation) /
+                                (totalTranslationY - stashedHandleTranslationYForAnimation)
                         bubbleBarView.alpha = fraction
                         bubbleBarView.scaleY =
                             BUBBLE_ANIMATION_INITIAL_SCALE_Y +
@@ -192,18 +231,16 @@
                     bubbleStashController.updateTaskbarTouchRegion()
                 }
             }
+            translationTracker.updateTyAndExpandIfNeeded(ty)
         }
         animator.addEndListener { _, _, _, canceled, _, _, _ ->
             // if the show animation was canceled, also cancel the hide animation. this is typically
             // canceled in this class, but could potentially be canceled elsewhere.
-            if (canceled) {
-                val hideAnimation = animatingBubble?.hideAnimation ?: return@addEndListener
-                scheduler.cancel(hideAnimation)
-                animatingBubble = null
-                bubbleBarView.onAnimatingBubbleCompleted()
-                bubbleBarView.relativePivotY = 1f
+            if (canceled || animatingBubble?.expand == true) {
+                cancelHideAnimation()
                 return@addEndListener
             }
+            moveToState(AnimatingBubble.State.IN)
             // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
             bubbleStashController.updateTaskbarTouchRegion()
         }
@@ -226,13 +263,14 @@
      */
     private fun buildBubbleBarToHandleAnimation() = Runnable {
         if (animatingBubble == null) return@Runnable
-        val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+        moveToState(AnimatingBubble.State.ANIMATING_OUT)
+        val offset = bubbleStashController.getDiffBetweenHandleAndBarCenters()
         val stashedHandleTranslationY =
-            bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+            bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
         // this is the total distance that both the stashed handle and the bar will be traveling
         val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
         bubbleStashController.setHandleTranslationY(totalTranslationY)
-        val animator = bubbleStashController.stashedHandlePhysicsAnimator
+        val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
         animator.setDefaultSpringConfig(springConfig)
         animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
         animator.addUpdateListener { handle, values ->
@@ -271,7 +309,6 @@
         animator.addEndListener { _, _, _, canceled, _, _, _ ->
             animatingBubble = null
             if (!canceled) bubbleStashController.stashBubbleBarImmediate()
-            bubbleBarView.onAnimatingBubbleCompleted()
             bubbleBarView.relativePivotY = 1f
             bubbleStashController.updateTaskbarTouchRegion()
         }
@@ -280,6 +317,8 @@
 
     /** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
     fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) {
+        // TODO b/346400677: handle animations for the same bubble interrupting each other
+        if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
         val bubbleView = b.view
         val animator = PhysicsAnimator.getInstance(bubbleView)
         if (animator.isRunning()) animator.cancel()
@@ -295,36 +334,49 @@
                 Runnable {
                     animatingBubble = null
                     bubbleStashController.showBubbleBarImmediate()
-                    bubbleBarView.onAnimatingBubbleCompleted()
                     bubbleStashController.updateTaskbarTouchRegion()
                 }
             }
-        animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+        animatingBubble =
+            AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
         scheduler.post(showAnimation)
         scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
     }
 
     private fun buildBubbleBarSpringInAnimation() = Runnable {
+        moveToState(AnimatingBubble.State.ANIMATING_IN)
         // prepare the bubble bar for the animation
-        bubbleBarView.onAnimatingBubbleStarted()
         bubbleBarView.translationY = bubbleBarView.height.toFloat()
         bubbleBarView.visibility = VISIBLE
         bubbleBarView.alpha = 1f
         bubbleBarView.scaleX = 1f
         bubbleBarView.scaleY = 1f
 
+        val translationTracker = TranslationTracker(bubbleBarView.translationY)
+
         val animator = PhysicsAnimator.getInstance(bubbleBarView)
         animator.setDefaultSpringConfig(springConfig)
         animator.spring(DynamicAnimation.TRANSLATION_Y, bubbleStashController.bubbleBarTranslationY)
-        animator.addUpdateListener { _, _ -> bubbleStashController.updateTaskbarTouchRegion() }
+        animator.addUpdateListener { _, values ->
+            val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+            translationTracker.updateTyAndExpandIfNeeded(ty)
+            bubbleStashController.updateTaskbarTouchRegion()
+        }
         animator.addEndListener { _, _, _, _, _, _, _ ->
+            if (animatingBubble?.expand == true) {
+                cancelHideAnimation()
+            } else {
+                moveToState(AnimatingBubble.State.IN)
+            }
             // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
             bubbleStashController.updateTaskbarTouchRegion()
         }
         animator.start()
     }
 
-    fun animateBubbleBarForCollapsed(b: BubbleBarBubble) {
+    fun animateBubbleBarForCollapsed(b: BubbleBarBubble, isExpanding: Boolean) {
+        // TODO b/346400677: handle animations for the same bubble interrupting each other
+        if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
         val bubbleView = b.view
         val animator = PhysicsAnimator.getInstance(bubbleView)
         if (animator.isRunning()) animator.cancel()
@@ -332,10 +384,10 @@
         val hideAnimation = Runnable {
             animatingBubble = null
             bubbleStashController.showBubbleBarImmediate()
-            bubbleBarView.onAnimatingBubbleCompleted()
             bubbleStashController.updateTaskbarTouchRegion()
         }
-        animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+        animatingBubble =
+            AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
         scheduler.post(showAnimation)
         scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
     }
@@ -346,27 +398,37 @@
      * the bubble bar moves back to its initial position with a spring animation.
      */
     private fun buildBubbleBarBounceAnimation() = Runnable {
-        bubbleBarView.onAnimatingBubbleStarted()
+        moveToState(AnimatingBubble.State.ANIMATING_IN)
         val ty = bubbleStashController.bubbleBarTranslationY
 
         val springBackAnimation = PhysicsAnimator.getInstance(bubbleBarView)
         springBackAnimation.setDefaultSpringConfig(springConfig)
         springBackAnimation.spring(DynamicAnimation.TRANSLATION_Y, ty)
+        springBackAnimation.addEndListener { _, _, _, _, _, _, _ ->
+            if (animatingBubble?.expand == true) {
+                bubbleBarView.isExpanded = true
+                cancelHideAnimation()
+            } else {
+                moveToState(AnimatingBubble.State.IN)
+            }
+        }
 
         // animate the bubble bar up and start the spring back down animation when it ends.
         ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
             .withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
-            .withEndAction { springBackAnimation.start() }
+            .withEndAction {
+                if (animatingBubble?.expand == true) bubbleBarView.isExpanded = true
+                springBackAnimation.start()
+            }
             .start()
     }
 
     /** Handles touching the animating bubble bar. */
     fun onBubbleBarTouchedWhileAnimating() {
         PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
-        bubbleStashController.stashedHandlePhysicsAnimator.cancelIfRunning()
+        bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
-        bubbleBarView.onAnimatingBubbleCompleted()
         bubbleBarView.relativePivotY = 1f
         animatingBubble = null
     }
@@ -376,8 +438,7 @@
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
         animatingBubble = null
-        bubbleStashController.stashedHandlePhysicsAnimator.cancel()
-        bubbleBarView.onAnimatingBubbleCompleted()
+        bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
         bubbleBarView.relativePivotY = 1f
         bubbleStashController.onNewBubbleAnimationInterrupted(
             /* isStashed= */ bubbleBarView.alpha == 0f,
@@ -385,8 +446,26 @@
         )
     }
 
-    private fun <T> PhysicsAnimator<T>.cancelIfRunning() {
-        if (isRunning()) cancel()
+    fun expandedWhileAnimating() {
+        val animatingBubble = animatingBubble ?: return
+        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
+            cancelHideAnimation()
+        }
+    }
+
+    private fun cancelHideAnimation() {
+        val hideAnimation = animatingBubble?.hideAnimation ?: return
+        scheduler.cancel(hideAnimation)
+        animatingBubble = null
+        bubbleBarView.relativePivotY = 1f
+        bubbleStashController.showBubbleBarImmediate()
+    }
+
+    private fun <T> PhysicsAnimator<T>?.cancelIfRunning() {
+        if (this?.isRunning() == true) cancel()
     }
 
     private fun ObjectAnimator.withDuration(duration: Long): ObjectAnimator {
@@ -404,4 +483,37 @@
         )
         return this
     }
+
+    private fun moveToState(state: AnimatingBubble.State) {
+        val animatingBubble = this.animatingBubble ?: return
+        this.animatingBubble = animatingBubble.copy(state = state)
+    }
+
+    /**
+     * 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
+     * position.
+     */
+    private inner class TranslationTracker(initialTy: Float) {
+        private var previousTy = initialTy
+        private var startedExpanding = false
+        private var reachedPeak = false
+
+        fun updateTyAndExpandIfNeeded(ty: Float) {
+            if (!reachedPeak) {
+                // the bubble bar is positioned at the bottom of the screen and moves up using
+                // negative ty values. the peak is reached the first time we see a value that is
+                // greater than the previous.
+                if (ty > previousTy) {
+                    reachedPeak = true
+                }
+            }
+            val expand = animatingBubble?.expand ?: false
+            if (reachedPeak && expand && !startedExpanding) {
+                bubbleBarView.isExpanded = true
+                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 59fc76c..48eb7de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -52,7 +52,7 @@
     /** Execute passed action only after controllers are initiated. */
     interface ControllersAfterInitAction {
         /** Execute action after controllers are initiated. */
-        fun runAfterInit(action: () -> Unit)
+        fun runAfterInit(action: Runnable)
     }
 
     /** Whether bubble bar is currently stashed */
@@ -143,6 +143,9 @@
     /** Set the translation Y for the stashed handle. */
     fun setHandleTranslationY(translationY: Float)
 
+    /** Returns the translation of the handle. */
+    fun getHandleTranslationY(): Float?
+
     /**
      * Returns bubble bar Y position according to [isBubblesShowingOnHome] and
      * [isBubblesShowingOnOverview] values. Default implementation only analyse
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
new file mode 100644
index 0000000..a55763b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.stashing
+
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
+
+/**
+ * Implementation of the [TaskbarHotseatDimensionsProvider] that take sizes from the
+ * [DeviceProfile].
+ */
+class DeviceProfileDimensionsProviderAdapter(
+    private val taskbarActivityContext: TaskbarActivityContext
+) : TaskbarHotseatDimensionsProvider {
+    override fun getTaskbarBottomSpace(): Int = deviceProfile().taskbarBottomMargin
+
+    override fun getTaskbarHeight(): Int = deviceProfile().taskbarHeight
+
+    override fun getHotseatBottomSpace(): Int = deviceProfile().hotseatBarBottomSpacePx
+
+    override fun getHotseatHeight(): Int = deviceProfile().hotseatCellHeightPx
+
+    private fun deviceProfile(): DeviceProfile = taskbarActivityContext.deviceProfile
+}
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 62fe221..1b65019 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -198,6 +198,8 @@
         // no op since does not have a handle view
     }
 
+    override fun getHandleTranslationY(): Float? = null
+
     private fun updateExpandedState(expand: Boolean) {
         if (bubbleBarViewController.isHiddenForNoBubbles) {
             // If there are no bubbles the bar is invisible, nothing to do here.
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 23e009b..1a4b982 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -242,6 +242,8 @@
         bubbleStashedHandleViewController?.setTranslationYForSwipe(translationY)
     }
 
+    override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
+
     private fun getStashTranslation(): Float {
         return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 92abebe..7d2d36d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -63,10 +63,10 @@
         val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
 
         allAppsButton.setIconDrawable(drawable)
-        allAppsButton.setPadding(/* left= */ padding)
+        allAppsButton.setPadding(padding)
         allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
 
-        // TODO(jagrutdesai) : add click listeners in future cl
+        // TODO(b/356465292) : add click listeners in future cl
         addView(allAppsButton)
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
new file mode 100644
index 0000000..26e71f7
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.customization
+
+import android.annotation.SuppressLint
+import android.content.Context
+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.views.ActivityContext
+import com.android.launcher3.views.IconButtonView
+
+/** Taskbar divider view container for customizable taskbar. */
+class TaskbarDividerContainer
+@JvmOverloads
+constructor(
+    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
+    private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+
+    override val spaceNeeded: Int
+        get() {
+            return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+        }
+
+    init {
+        setUpIcon()
+    }
+
+    @SuppressLint("UseCompatLoadingForDrawables")
+    fun setUpIcon() {
+        val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
+        val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+
+        taskbarDivider.setIconDrawable(drawable)
+        taskbarDivider.setPadding(padding)
+
+        // TODO(b/356465292):: add click listeners in future cl
+        addView(taskbarDivider)
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index dea5c1b..bb33c18 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -45,6 +45,7 @@
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
+import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
 import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
 import static com.android.launcher3.popup.SystemShortcut.INSTALL;
 import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
@@ -75,6 +76,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.ShortcutInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -215,7 +217,8 @@
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
+public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
+        SystemShortcut.BubbleActivityStarter {
     private static final boolean TRACE_LAYOUTS =
             SystemProperties.getBoolean("persist.debug.trace_layouts", false);
     private static final String TRACE_RELAYOUT_CLASS =
@@ -466,6 +469,9 @@
         if (Flags.enablePrivateSpace()) {
             shortcuts.add(UNINSTALL_APP);
         }
+        if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+            shortcuts.add(BUBBLE_SHORTCUT);
+        }
         return shortcuts.stream();
     }
 
@@ -1382,10 +1388,11 @@
      */
     public void launchSplitTasks(
             @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
-        // Top/left and bottom/right tasks respectively.
-        Task task1 = groupTask.task1;
+        // SplitBounds can be null if coming from Taskbar launch.
+        final boolean firstTaskIsLeftTopTask = isFirstTaskLeftTopTask(groupTask);
         // task2 should never be null when calling this method. Allow a crash to catch invalid calls
-        Task task2 = groupTask.task2;
+        Task task1 = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
+        Task task2 = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
         mSplitSelectStateController.launchExistingSplitPair(
                 null /* launchingTaskView */,
                 task1.key.id,
@@ -1399,12 +1406,23 @@
                 remoteTransition);
     }
 
+    private static boolean isFirstTaskLeftTopTask(@NonNull GroupTask groupTask) {
+        return groupTask.mSplitBounds == null
+                || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
+    }
+
     /**
      * Launches two apps as an app pair.
      */
     public void launchAppPair(AppPairIcon appPairIcon) {
+        // Potentially show the Taskbar education once the app pair launch finishes
         mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon,
-                CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE);
+                CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE,
+                (success) -> {
+                    if (success && mTaskbarUIController != null) {
+                        mTaskbarUIController.showEduOnAppLaunch();
+                    }
+                });
     }
 
     public boolean canStartHomeSafely() {
@@ -1436,6 +1454,18 @@
         return true;
     }
 
+    @Override
+    public void showShortcutBubble(ShortcutInfo info) {
+        if (info == null) return;
+        SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
+    }
+
+    @Override
+    public void showAppBubble(Intent intent) {
+        if (intent == null || intent.getPackage() == null) return;
+        SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
+    }
+
     private static final class LauncherTaskViewController extends
             TaskViewTouchController<QuickstepLauncher> {
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index d98e608..cb2c324 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -58,8 +58,6 @@
     /* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/
     private boolean mCanIntercept;
 
-    private boolean mIsTrackpadReverseScroll;
-
     public StatusBarTouchController(Launcher l) {
         mLauncher = l;
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(mLauncher);
@@ -95,8 +93,6 @@
             }
             mDownEvents.clear();
             mDownEvents.put(pid, new PointF(ev.getX(), ev.getY()));
-            mIsTrackpadReverseScroll = !mLauncher.isNaturalScrollingEnabled()
-                    && isTrackpadScroll(ev);
         } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
             // Check!! should only set it only when threshold is not entered.
             mDownEvents.put(pid, new PointF(ev.getX(idx), ev.getY(idx)));
@@ -107,9 +103,6 @@
         if (action == ACTION_MOVE && mDownEvents.contains(pid)) {
             float dy = ev.getY(idx) - mDownEvents.get(pid).y;
             float dx = ev.getX(idx) - mDownEvents.get(pid).x;
-            if (mIsTrackpadReverseScroll) {
-                dy = -dy;
-            }
             // Currently input dispatcher will not do touch transfer if there are more than
             // one touch pointer. Hence, even if slope passed, only set the slippery flag
             // when there is single touch event. (context: InputDispatcher.cpp line 1445)
@@ -134,7 +127,6 @@
             mLauncher.getStatsLogManager().logger()
                     .log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN);
             setWindowSlippery(false);
-            mIsTrackpadReverseScroll = false;
             return true;
         }
         return true;
@@ -161,9 +153,9 @@
     }
 
     private boolean canInterceptTouch(MotionEvent ev) {
-        if (!mLauncher.isInState(LauncherState.NORMAL) ||
-                AbstractFloatingView.getTopOpenViewWithType(mLauncher,
-                        AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) != null) {
+        if (isTrackpadScroll(ev) || !mLauncher.isInState(LauncherState.NORMAL)
+                || AbstractFloatingView.getTopOpenViewWithType(mLauncher,
+                AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) != null) {
             return false;
         } else {
             // For NORMAL state, only listen if the event originated above the navbar height
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 3c7f335..eafc5b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -22,9 +22,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.VibrationEffect;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.animation.Interpolator;
 
 import com.android.app.animation.Interpolators;
@@ -67,7 +67,7 @@
     protected final CONTAINER mContainer;
     private final SingleAxisSwipeDetector mDetector;
     private final RecentsView mRecentsView;
-    private final int[] mTempCords = new int[2];
+    private final Rect mTempRect = new Rect();
     private final boolean mIsRtl;
 
     private AnimatorPlaybackController mCurrentAnimation;
@@ -252,10 +252,8 @@
                     mTaskBeingDragged, maxDuration, currentInterpolator);
 
             // Since the thumbnail is what is filling the screen, based the end displacement on it.
-            View thumbnailView = mTaskBeingDragged.getFirstSnapshotView();
-            mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
-            dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
-            mEndDisplacement = secondaryLayerDimension - mTempCords[1];
+            mTaskBeingDragged.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+            mEndDisplacement = secondaryLayerDimension - mTempRect.bottom;
         }
         mEndDisplacement *= verticalFactor;
         mCurrentAnimation = pa.createPlaybackController();
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d7ed305..6109fd8 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -105,6 +105,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -140,6 +141,7 @@
 import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskContainer;
 import com.android.quickstep.views.TaskView;
+import com.android.systemui.contextualeducation.GestureType;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -989,7 +991,6 @@
                 dp = dp.copy(mContext);
             }
             dp.updateInsets(targets.homeContentInsets);
-            dp.updateIsSeascape(mContext);
             initTransitionEndpoints(dp);
             orientationState.setMultiWindowMode(dp.isMultiWindowMode);
         }
@@ -1409,6 +1410,8 @@
             if (mRecentsAnimationController != null) {
                 mRecentsAnimationController.detachNavigationBarFromApp(true);
             }
+            ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
+                    mGestureState.isTrackpadGesture(), GestureType.HOME);
         } else if (endTarget == RECENTS) {
             if (mRecentsView != null) {
                 int nearestPage = mRecentsView.getDestinationPage();
@@ -1433,6 +1436,8 @@
                 if (!mGestureState.isHandlingAtomicEvent() || isScrolling) {
                     duration = Math.max(duration, mRecentsView.getScroller().getDuration());
                 }
+                ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
+                        mGestureState.isTrackpadGesture(), GestureType.OVERVIEW);
             }
         } else if (endTarget == LAST_TASK && mRecentsView != null
                 && mRecentsView.getNextPage() != mRecentsView.getRunningTaskIndex()) {
@@ -2100,7 +2105,6 @@
             // If there are no targets, then we don't need to capture anything
             mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
         } else {
-            boolean finishTransitionPosted = false;
             // If we already have cached screenshot(s) from running tasks, skip update
             boolean shouldUpdate = false;
             int[] runningTaskIds = mGestureState.getRunningTaskIds(mIsSwipeForSplit);
@@ -2124,45 +2128,32 @@
                         }
 
                         MAIN_EXECUTOR.execute(() -> {
-                            if (!updateThumbnail(false /* refreshView */)) {
-                                setScreenshotCapturedState();
-                            }
+                            updateThumbnail();
+                            setScreenshotCapturedState();
                         });
                     });
                     return;
                 }
 
-                finishTransitionPosted = updateThumbnail(false /* refreshView */);
+                updateThumbnail();
             }
 
-            if (!finishTransitionPosted) {
-                setScreenshotCapturedState();
-            }
+            setScreenshotCapturedState();
         }
     }
 
     // Returns whether finish transition was posted.
-    private boolean updateThumbnail(boolean refreshView) {
+    private void updateThumbnail() {
         if (mGestureState.getEndTarget() == HOME
                 || mGestureState.getEndTarget() == NEW_TASK
                 || mGestureState.getEndTarget() == ALL_APPS
                 || mRecentsView == null) {
             // Capture the screenshot before finishing the transition to home or quickswitching to
             // ensure it's taken in the correct orientation, but no need to update the thumbnail.
-            return false;
+            return;
         }
 
-        boolean finishTransitionPosted = false;
-        TaskView updatedTaskView = mRecentsView.updateThumbnail(mTaskSnapshotCache, refreshView);
-        if (updatedTaskView != null && refreshView && !mCanceled) {
-            // Defer finishing the animation until the next launcher frame with the
-            // new thumbnail
-            finishTransitionPosted = ViewUtils.postFrameDrawn(updatedTaskView,
-                    () -> mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED),
-                    this::isCanceled);
-        }
-
-        return finishTransitionPosted;
+        mRecentsView.updateThumbnail(mTaskSnapshotCache);
     }
 
     private void setScreenshotCapturedState() {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 00cd60b..293944d 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -31,7 +31,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.graphics.Color;
 import android.view.MotionEvent;
 
 import androidx.annotation.Nullable;
@@ -133,7 +132,7 @@
     public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
         TaskbarUIController controller = getTaskbarController();
         boolean isEventOverBubbleBarStashHandle =
-                controller != null && controller.isEventOverBubbleBarStashHandle(ev);
+                controller != null && controller.isEventOverBubbleBarViews(ev);
         return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
                 || isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
     }
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 358f644..fbc0d14 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -34,7 +34,7 @@
     abstractFloatingViewHelper: AbstractFloatingViewHelper
 ) :
     SystemShortcut<RecentsViewContainer>(
-        R.drawable.ic_caption_desktop_button_foreground,
+        R.drawable.ic_desktop,
         R.string.recent_task_option_desktop,
         container,
         taskContainer.itemInfo,
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index da7a98f..32e2389 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -128,15 +128,11 @@
                     mController::finishAnimationToApp);
         } else {
             RemoteAnimationTarget[] nonAppTargets;
-            if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-                nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(appTargets);
-            } else {
-                final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
-                final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
-                classifyTargets(appTargets, apps, nonApps);
-                appTargets = apps.toArray(new RemoteAnimationTarget[apps.size()]);
-                nonAppTargets = nonApps.toArray(new RemoteAnimationTarget[nonApps.size()]);
-            }
+            final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
+            final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
+            classifyTargets(appTargets, apps, nonApps);
+            appTargets = apps.toArray(new RemoteAnimationTarget[apps.size()]);
+            nonAppTargets = nonApps.toArray(new RemoteAnimationTarget[nonApps.size()]);
             if (nonAppTargets == null) {
                 nonAppTargets = new RemoteAnimationTarget[0];
             }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 3511701..ead5b7b 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -23,7 +23,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
-import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -48,7 +47,6 @@
 import android.view.IRecentsAnimationRunner;
 import android.view.IRemoteAnimationRunner;
 import android.view.MotionEvent;
-import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.window.IOnBackInvokedCallback;
@@ -94,6 +92,7 @@
 import com.android.wm.shell.recents.IRecentTasks;
 import com.android.wm.shell.recents.IRecentTasksListener;
 import com.android.wm.shell.shared.IShellTransitions;
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
 import com.android.wm.shell.splitscreen.ISplitScreen;
@@ -240,6 +239,17 @@
     }
 
     @Override
+    public void updateContextualEduStats(boolean isTrackpadGesture, String gestureType) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.updateContextualEduStats(isTrackpadGesture, gestureType);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call updateContextualEduStats");
+            }
+        }
+    }
+
+    @Override
     public void setHomeRotationEnabled(boolean enabled) {
         if (mSystemUiProxy != null) {
             try {
@@ -894,6 +904,36 @@
         }
     }
 
+    /**
+     * Tells SysUI to show a shortcut bubble.
+     *
+     * @param info the shortcut info used to create or identify the bubble.
+     */
+    public void showShortcutBubble(ShortcutInfo info) {
+        try {
+            if (mBubbles != null) {
+                mBubbles.showShortcutBubble(info);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call show bubble for shortcut");
+        }
+    }
+
+    /**
+     * Tells SysUI to show a bubble of an app.
+     *
+     * @param intent the intent used to create the bubble.
+     */
+    public void showAppBubble(Intent intent) {
+        try {
+            if (mBubbles != null) {
+                mBubbles.showAppBubble(intent);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call show bubble for app");
+        }
+    }
+
     //
     // Splitscreen
     //
@@ -1000,77 +1040,6 @@
         }
     }
 
-    /**
-     * Start multiple tasks in split-screen simultaneously.
-     */
-    public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
-            Bundle options2, @StagePosition int splitPosition,
-            @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
-            InstanceId instanceId) {
-        if (mSystemUiProxy != null) {
-            try {
-                mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
-                        splitPosition, snapPosition, adapter, instanceId);
-            } catch (RemoteException e) {
-                Log.w(TAG, splitFailureMessage(
-                        "startTasksWithLegacyTransition", "RemoteException"), e);
-            }
-        }
-    }
-
-    public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1,
-            Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition,
-            @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
-            InstanceId instanceId) {
-        if (mSystemUiProxy != null) {
-            try {
-                mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
-                        options1, taskId, options2, splitPosition, snapPosition, adapter,
-                        instanceId);
-            } catch (RemoteException e) {
-                Log.w(TAG, splitFailureMessage(
-                        "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
-            }
-        }
-    }
-
-    public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
-            int taskId, Bundle options2, @StagePosition int splitPosition,
-            @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
-            InstanceId instanceId) {
-        if (mSystemUiProxy != null) {
-            try {
-                mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
-                        taskId, options2, splitPosition, snapPosition, adapter, instanceId);
-            } catch (RemoteException e) {
-                Log.w(TAG, splitFailureMessage(
-                        "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
-            }
-        }
-    }
-
-    /**
-     * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
-     * non-null shortcut info means to start the app as a shortcut.
-     */
-    public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, int userId1,
-            @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
-            PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2,
-            @Nullable Bundle options2, @StagePosition int sidePosition,
-            @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
-            InstanceId instanceId) {
-        if (mSystemUiProxy != null) {
-            try {
-                mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, userId1,
-                        shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
-                        sidePosition, snapPosition, adapter, instanceId);
-            } catch (RemoteException e) {
-                Log.w(TAG, splitFailureMessage(
-                        "startIntentsWithLegacyTransition", "RemoteException"), e);
-            }
-        }
-    }
-
     public void startShortcut(String packageName, String shortcutId, int position,
             Bundle options, UserHandle user, InstanceId instanceId) {
         if (mSplitScreen != null) {
@@ -1105,36 +1074,6 @@
         }
     }
 
-    /**
-     * Call this when going to recents so that shell can set-up and provide appropriate leashes
-     * for animation (eg. DividerBar).
-     *
-     * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
-     */
-    @Nullable
-    public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
-        if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS && mSplitScreen != null) {
-            try {
-                return mSplitScreen.onGoingToRecentsLegacy(apps);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed call onGoingToRecentsLegacy");
-            }
-        }
-        return null;
-    }
-
-    @Nullable
-    public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
-        if (mSplitScreen != null) {
-            try {
-                return mSplitScreen.onStartingSplitLegacy(apps);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed call onStartingSplitLegacy");
-            }
-        }
-        return null;
-    }
-
     //
     // One handed
     //
@@ -1444,7 +1383,7 @@
 
     private boolean shouldEnableRunningTasksForDesktopMode() {
         return DesktopModeStatus.canEnterDesktopMode(mContext)
-                && enableDesktopWindowingTaskbarRunningApps();
+                && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext);
     }
 
     private boolean handleMessageAsync(Message msg) {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 723aa03..ab80a8c 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -18,6 +18,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 
 import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
@@ -44,6 +45,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.SystemUiFlagUtils;
@@ -264,12 +266,7 @@
                     }
                 }
 
-                RemoteAnimationTarget[] nonAppTargets = ENABLE_SHELL_TRANSITIONS
-                        ? null : getSystemUiProxy().onStartingSplitLegacy(
-                                appearedTaskTargets);
-                if (nonAppTargets == null) {
-                    nonAppTargets = new RemoteAnimationTarget[0];
-                }
+                RemoteAnimationTarget[] nonAppTargets = new RemoteAnimationTarget[0];
                 if ((containerInterface.isInLiveTileMode()
                             || mLastGestureState.getEndTarget() == RECENTS
                             || isNonRecentsStartedTasksAppeared(appearedTaskTargets))
@@ -339,6 +336,28 @@
                 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);
+
+                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);
+                    }
+                });
+            }
+
             mRecentsAnimationStartPending = getSystemUiProxy()
                     .startRecentsActivity(intent, options, mCallbacks);
             if (enableHandleDelayedGestureCallbacks()) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bd44283..1a09691 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -232,9 +232,13 @@
                         TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
                         taskRectTranslationSecondary);
 
-                // Fade in the task during the initial 20% of the animation
-                out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
-                        clampToProgress(LINEAR, 0, 0.2f));
+                if (v instanceof DesktopTaskView) {
+                    targetHandle.getTransformParams().setTargetAlpha(1f);
+                } else {
+                    // Fade in the task during the initial 20% of the animation
+                    out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0,
+                            1, clampToProgress(LINEAR, 0, 0.2f));
+                }
             }
         }
 
@@ -558,7 +562,7 @@
     /**
      * Start recents to desktop animation
      */
-    public static void composeRecentsDesktopLaunchAnimator(
+    public static AnimatorSet composeRecentsDesktopLaunchAnimator(
             @NonNull DesktopTaskView launchingTaskView,
             @NonNull StateManager stateManager, @Nullable DepthController depthController,
             @NonNull TransitionInfo transitionInfo,
@@ -588,7 +592,7 @@
                 true /* launcherClosing */, stateManager, launchingTaskView.getRecentsView(),
                 depthController);
 
-        animatorSet.start();
+        return animatorSet;
     }
 
     public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 6ed05c8..3cf0542 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -28,7 +28,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -48,7 +47,6 @@
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.wm.shell.splitscreen.ISplitScreenListener;
 
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -63,10 +61,6 @@
 public class TopTaskTracker extends ISplitScreenListener.Stub
         implements TaskStackChangeListener, SafeCloseable {
 
-    private static final String TAG = "TopTaskTracker";
-
-    private static final boolean DEBUG = true;
-
     public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
             new MainThreadInitializedObject<>(TopTaskTracker::new);
 
@@ -98,19 +92,10 @@
     @Override
     public void onTaskRemoved(int taskId) {
         mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
-        if (DEBUG) {
-            Log.i(TAG, "onTaskRemoved: taskId=" + taskId);
-        }
     }
 
     @Override
     public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
-        if (!mOrderedTaskList.isEmpty()
-                && mOrderedTaskList.getFirst().taskId != taskInfo.taskId
-                && DEBUG) {
-            Log.i(TAG, "onTaskMovedToFront: (moved taskInfo to front) taskId=" + taskInfo.taskId
-                    + ", baseIntent=" + taskInfo.baseIntent);
-        }
         mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
         mOrderedTaskList.addFirst(taskInfo);
 
@@ -121,11 +106,6 @@
             final RunningTaskInfo topTaskOnHomeDisplay = mOrderedTaskList.stream()
                     .filter(rto -> rto.displayId == DEFAULT_DISPLAY).findFirst().orElse(null);
             if (topTaskOnHomeDisplay != null) {
-                if (DEBUG) {
-                    Log.i(TAG, "onTaskMovedToFront: (removing top task on home display) taskId="
-                            + topTaskOnHomeDisplay.taskId
-                            + ", baseIntent=" + topTaskOnHomeDisplay.baseIntent);
-                }
                 mOrderedTaskList.removeIf(rto -> rto.taskId == topTaskOnHomeDisplay.taskId);
                 mOrderedTaskList.addFirst(topTaskOnHomeDisplay);
             }
@@ -139,10 +119,6 @@
                 if (info.taskId != taskInfo.taskId
                         && info.taskId != mMainStagePosition.taskId
                         && info.taskId != mSideStagePosition.taskId) {
-                    if (DEBUG) {
-                        Log.i(TAG, "onTaskMovedToFront: (removing task list overflow) taskId="
-                                + taskInfo.taskId + ", baseIntent=" + taskInfo.baseIntent);
-                    }
                     itr.remove();
                     return;
                 }
@@ -152,9 +128,6 @@
 
     @Override
     public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
-        if (DEBUG) {
-            Log.i(TAG, "onStagePositionChanged: stage=" + stage + ", position=" + position);
-        }
         if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
             mMainStagePosition.stagePosition = position;
         } else {
@@ -164,10 +137,6 @@
 
     @Override
     public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
-        if (DEBUG) {
-            Log.i(TAG, "onTaskStageChanged: taskId=" + taskId
-                    + ", stage=" + stage + ", visible=" + visible);
-        }
         // If a task is not visible anymore or has been moved to undefined, stop tracking it.
         if (!visible || stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
             if (mMainStagePosition.taskId == taskId) {
@@ -187,18 +156,11 @@
 
     @Override
     public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
-        if (DEBUG) {
-            Log.i(TAG, "onActivityPinned: packageName=" + packageName
-                    + ", userId=" + userId + ", stackId=" + stackId);
-        }
         mPinnedTaskId = taskId;
     }
 
     @Override
     public void onActivityUnpinned() {
-        if (DEBUG) {
-            Log.i(TAG, "onActivityUnpinned");
-        }
         mPinnedTaskId = INVALID_TASK_ID;
     }
 
@@ -250,21 +212,6 @@
         return new CachedTaskInfo(tasks);
     }
 
-    public void dump(String prefix, PrintWriter writer) {
-        writer.println(prefix + "TopTaskTracker:");
-
-        writer.println(prefix + "\tmOrderedTaskList=[");
-        for (RunningTaskInfo taskInfo : mOrderedTaskList) {
-            writer.println(prefix + "\t\t(taskId=" + taskInfo.taskId
-                    + "; baseIntent=" + taskInfo.baseIntent
-                    + "; isRunning=" + taskInfo.isRunning + ")");
-        }
-        writer.println(prefix + "\t]");
-        writer.println(prefix + "\tmMainStagePosition=" + mMainStagePosition);
-        writer.println(prefix + "\tmSideStagePosition=" + mSideStagePosition);
-        writer.println(prefix + "\tmPinnedTaskId=" + mPinnedTaskId);
-    }
-
     /**
      * Class to provide information about a task which can be safely cached and do not change
      * during the lifecycle of the task.
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a499482..88ab528 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1610,7 +1610,6 @@
         pw.println("\tmConsumer=" + mConsumer.getName());
         ActiveGestureLog.INSTANCE.dump("", pw);
         RecentsModel.INSTANCE.get(this).dump("", pw);
-        TopTaskTracker.INSTANCE.get(this).dump("", pw);
         if (mTaskAnimationManager != null) {
             mTaskAnimationManager.dump("", pw);
         }
diff --git a/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java b/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java
new file mode 100644
index 0000000..d470b88
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.contextualeducation;
+
+import android.content.Context;
+
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.contextualeducation.GestureType;
+
+/**
+ * A class to update contextual education data via {@link SystemUiProxy}
+ */
+public class SystemContextualEduStatsManager extends ContextualEduStatsManager {
+    private Context mContext;
+
+    public SystemContextualEduStatsManager(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
+        SystemUiProxy.INSTANCE.get(mContext).updateContextualEduStats(isTrackpadGesture,
+                gestureType.name());
+    }
+
+    @Override
+    public void close() {
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 95295b0..9a99d4a 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -321,8 +321,9 @@
         if (controllers == null) {
             return false;
         }
-        if (controllers.bubbleStashController.isStashed()) {
-            return controllers.bubbleStashedHandleViewController.containsX((int) x);
+        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;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index f89888a..54653fa 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -782,7 +782,6 @@
                 (RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
         if (!mTutorialFragment.isLargeScreen()) {
             DeviceProfile dp = mTutorialFragment.getDeviceProfile();
-            dp.updateIsSeascape(mContext);
 
             hotseatLayoutParams.addRule(dp.isLandscape
                     ? (dp.isSeascape()
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index d5aaed5..4f7a541 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -46,5 +46,5 @@
      * 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 setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
+    fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
 }
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 0714170..6f9d157 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -17,115 +17,135 @@
 package com.android.quickstep.recents.data
 
 import android.graphics.drawable.Drawable
+import com.android.launcher3.util.coroutines.DispatcherProvider
 import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
 import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
 import com.android.quickstep.util.GroupTask
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.ThumbnailData
 import kotlin.coroutines.resume
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
 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.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
 
 @OptIn(ExperimentalCoroutinesApi::class)
 class TasksRepository(
     private val recentsModel: RecentTasksDataSource,
     private val taskThumbnailDataSource: TaskThumbnailDataSource,
     private val taskIconDataSource: TaskIconDataSource,
+    recentsCoroutineScope: CoroutineScope,
+    private val dispatcherProvider: DispatcherProvider,
 ) : RecentTasksRepository {
     private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
-    private val _taskData =
-        groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
     private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
     private val thumbnailOverride = MutableStateFlow(mapOf<Int, ThumbnailData>())
 
-    private val taskData: Flow<List<Task>> =
-        combine(_taskData, getThumbnailQueryResults(), getIconQueryResults(), thumbnailOverride) {
-            tasks,
-            thumbnailQueryResults,
-            iconQueryResults,
-            thumbnailOverride ->
-            tasks.forEach { task ->
-                // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
-                task.thumbnail =
-                    thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
-
-                // TODO(b/352331675) don't load icons for DesktopTaskView
-                // Add retrieved icons + remove unnecessary icons
-                task.icon = iconQueryResults[task.key.id]?.icon
-                task.titleDescription = iconQueryResults[task.key.id]?.contentDescription
-                task.title = iconQueryResults[task.key.id]?.title
-            }
-            tasks
+    private val taskData =
+        groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
+    private val visibleTasks =
+        combine(taskData, visibleTaskIds) { tasks, visibleIds ->
+            tasks.filter { it.key.id in visibleIds }
         }
 
+    private val iconQueryResults: Flow<Map<Int, TaskIconQueryResponse?>> =
+        visibleTasks
+            .map { visibleTasksList -> visibleTasksList.map(::getIconDataRequest) }
+            .flatMapLatest { iconRequestFlows: List<IconDataRequest> ->
+                if (iconRequestFlows.isEmpty()) {
+                    flowOf(emptyMap())
+                } else {
+                    combine(iconRequestFlows) { it.toMap() }
+                }
+            }
+            .distinctUntilChanged()
+
+    private val thumbnailQueryResults: Flow<Map<Int, ThumbnailData?>> =
+        visibleTasks
+            .map { visibleTasksList -> visibleTasksList.map(::getThumbnailDataRequest) }
+            .flatMapLatest { thumbnailRequestFlows: List<ThumbnailDataRequest> ->
+                if (thumbnailRequestFlows.isEmpty()) {
+                    flowOf(emptyMap())
+                } else {
+                    combine(thumbnailRequestFlows) { it.toMap() }
+                }
+            }
+            .distinctUntilChanged()
+
+    private val augmentedTaskData: Flow<List<Task>> =
+        combine(taskData, thumbnailQueryResults, iconQueryResults, thumbnailOverride) {
+                tasks,
+                thumbnailQueryResults,
+                iconQueryResults,
+                thumbnailOverride ->
+                tasks.onEach { task ->
+                    // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
+                    task.thumbnail =
+                        thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
+
+                    // TODO(b/352331675) don't load icons for DesktopTaskView
+                    // Add retrieved icons + remove unnecessary icons
+                    val iconQueryResult = iconQueryResults[task.key.id]
+                    task.icon = iconQueryResult?.icon
+                    task.titleDescription = iconQueryResult?.contentDescription
+                    task.title = iconQueryResult?.title
+                }
+            }
+            .flowOn(dispatcherProvider.io)
+            .shareIn(recentsCoroutineScope, SharingStarted.WhileSubscribed(), replay = 1)
+
     override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
         if (forceRefresh) {
             recentsModel.getTasks { groupedTaskData.value = it }
         }
-        return taskData
+        return augmentedTaskData
     }
 
     override fun getTaskDataById(taskId: Int): Flow<Task?> =
-        taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+        augmentedTaskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
 
     override fun getThumbnailById(taskId: Int): Flow<ThumbnailData?> =
         getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId }
 
     override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
         this.visibleTaskIds.value = visibleTaskIdList.toSet()
-        setThumbnailOverride(thumbnailOverride.value)
+        addOrUpdateThumbnailOverride(emptyMap())
     }
 
-    override fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+    override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
         this.thumbnailOverride.value =
-            thumbnailOverride.filterKeys(this.visibleTaskIds.value::contains).toMap()
+            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? =
-                    suspendCancellableCoroutine { continuation ->
-                        val cancellableTask =
-                            taskThumbnailDataSource.getThumbnailInBackground(task) {
-                                continuation.resume(it)
-                            }
-                        continuation.invokeOnCancellation { cancellableTask?.cancel() }
-                    }
-                emit(task.key.id to thumbnailDataResult)
+    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() }
+                }
             }
-            .distinctUntilChanged()
-
-    /**
-     * This is a Flow that makes a query for thumbnail data to the [taskThumbnailDataSource] for
-     * each visible task. It then collects the responses and returns them in a Map as soon as they
-     * are available.
-     */
-    private fun getThumbnailQueryResults(): Flow<Map<Int, ThumbnailData?>> {
-        val visibleTasks =
-            combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
-                tasks.filter { it.key.id in visibleIds }
-            }
-        val visibleThumbnailDataRequests: Flow<List<ThumbnailDataRequest>> =
-            visibleTasks.map { visibleTasksList -> visibleTasksList.map(::getThumbnailDataRequest) }
-        return visibleThumbnailDataRequests.flatMapLatest {
-            thumbnailRequestFlows: List<ThumbnailDataRequest> ->
-            if (thumbnailRequestFlows.isEmpty()) {
-                flowOf(emptyMap())
-            } else {
-                combine(thumbnailRequestFlows) { it.toMap() }
-            }
-        }
+        emit(task.key.id to thumbnailDataResult)
     }
 
     /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
@@ -133,43 +153,29 @@
         flow {
                 emit(task.key.id to task.getTaskIconQueryResponse())
                 val iconDataResponse: TaskIconQueryResponse? =
-                    suspendCancellableCoroutine { continuation ->
-                        val cancellableTask =
-                            taskIconDataSource.getIconInBackground(task) {
-                                icon,
-                                contentDescription,
-                                title ->
-                                icon.constantState?.let {
-                                    continuation.resume(
-                                        TaskIconQueryResponse(
-                                            it.newDrawable().mutate(),
-                                            contentDescription,
-                                            title
+                    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() }
+                            continuation.invokeOnCancellation { cancellableTask?.cancel() }
+                        }
                     }
                 emit(task.key.id to iconDataResponse)
             }
             .distinctUntilChanged()
-
-    private fun getIconQueryResults(): Flow<Map<Int, TaskIconQueryResponse?>> {
-        val visibleTasks =
-            combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
-                tasks.filter { it.key.id in visibleIds }
-            }
-        val visibleIconDataRequests: Flow<List<IconDataRequest>> =
-            visibleTasks.map { visibleTasksList -> visibleTasksList.map(::getIconDataRequest) }
-        return visibleIconDataRequests.flatMapLatest { iconRequestFlows: List<IconDataRequest> ->
-            if (iconRequestFlows.isEmpty()) {
-                flowOf(emptyMap())
-            } else {
-                combine(iconRequestFlows) { it.toMap() }
-            }
-        }
-    }
 }
 
 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 eba7688..d8156b1 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.util.Log
 import android.view.View
+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.TasksRepository
@@ -36,6 +37,10 @@
 import com.android.quickstep.task.viewmodel.TaskViewModel
 import com.android.quickstep.views.TaskViewType
 import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
 
 internal typealias RecentsScopeId = String
 
@@ -53,11 +58,20 @@
     private fun startDefaultScope(appContext: Context) {
         createScope(DEFAULT_SCOPE_ID).apply {
             set(RecentsViewData::class.java.simpleName, RecentsViewData())
+            val recentsCoroutineScope =
+                CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
+            set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
 
             // Create RecentsTaskRepository singleton
             val recentTasksRepository: RecentTasksRepository =
                 with(RecentsModel.INSTANCE.get(appContext)) {
-                    TasksRepository(this, thumbnailCache, iconCache)
+                    TasksRepository(
+                        this,
+                        thumbnailCache,
+                        iconCache,
+                        recentsCoroutineScope,
+                        ProductionDispatchers
+                    )
                 }
             set(RecentTasksRepository::class.java.simpleName, recentTasksRepository)
         }
@@ -137,7 +151,13 @@
             when (modelClass) {
                 RecentTasksRepository::class.java -> {
                     with(RecentsModel.INSTANCE.get(appContext)) {
-                        TasksRepository(this, thumbnailCache, iconCache)
+                        TasksRepository(
+                            this,
+                            thumbnailCache,
+                            iconCache,
+                            get(),
+                            ProductionDispatchers
+                        )
                     }
                 }
                 RecentsViewData::class.java -> RecentsViewData()
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index 7205fc8..b1f46a3 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -58,15 +58,15 @@
         recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
     }
 
-    fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
-        recentsTasksRepository.setThumbnailOverride(thumbnailOverride)
+    fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+        recentsTasksRepository.addOrUpdateThumbnailOverride(thumbnailOverride)
     }
 
     suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
         combine(
                 updatedThumbnails.map {
                     recentsTasksRepository.getThumbnailById(it.key).filter { thumbnailData ->
-                        thumbnailData == it.value
+                        thumbnailData?.snapshotId == it.value.snapshotId
                     }
                 }
             ) {}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 1a20439..ac4032c 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -74,6 +74,7 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Controller class that handles app pair interactions: saving, modifying, deleting, etc.
@@ -232,8 +233,11 @@
      *
      * @param cuj Should be an integer from {@link Cuj} or -1 if no CUJ needs to be logged for jank
      *            monitoring
+     * @param callback Called after the app pair launch finishes animating, or null if no method is
+     *                 to be called
      */
-    public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
+    public void launchAppPair(AppPairIcon appPairIcon, int cuj,
+            @Nullable Consumer<Boolean> callback) {
         WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
         WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
         ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
@@ -273,12 +277,19 @@
                     mSplitSelectStateController.setLaunchingIconView(appPairIcon);
 
                     mSplitSelectStateController.launchSplitTasks(
-                            AppPairsController.convertRankToSnapPosition(app1.rank));
+                            AppPairsController.convertRankToSnapPosition(app1.rank), callback);
                 }
         );
     }
 
     /**
+     * Launches an app pair but does not specify a callback
+     */
+    public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
+        launchAppPair(appPairIcon, cuj, null);
+    }
+
+    /**
      * Returns an AppInfo associated with the app for the given ComponentKey, or null if no such
      * package exists in the AllAppsStore.
      */
diff --git a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
index 0ce54ad..2e3dee6 100644
--- a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
+++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
@@ -81,7 +81,7 @@
             try {
                 mActivityTaskManager.requestAssistDataForTask(
                         new AssistDataReceiver(callback, this), taskId, mPackageName,
-                        mAttributionTag);
+                        mAttributionTag, false /* fetchStructure */);
             } catch (RemoteException e) {
                 Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
             }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d913b91..2ff8e45 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,7 +16,6 @@
 
 package com.android.quickstep.util;
 
-import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTED_SECOND_APP;
@@ -60,8 +59,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.RemoteTransition;
@@ -94,13 +91,11 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SplitSelectionListener;
 import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.SplitInstructionsView;
-import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -276,17 +271,15 @@
                     // Loop through tasks in reverse, since they are ordered with recent tasks last
                     for (int j = taskGroups.size() - 1; j >= 0; j--) {
                         GroupTask groupTask = taskGroups.get(j);
-                        Task task1 = groupTask.task1;
-                        // Don't add duplicate Tasks
-                        if (isInstanceOfComponent(task1, key)
-                                && !Arrays.asList(lastActiveTasks).contains(task1)) {
-                            lastActiveTask = task1;
-                            break;
+                        // Account for desktop cases where there can be N tasks in the group
+                        for (Task task : groupTask.getTasks()) {
+                            if (isInstanceOfComponent(task, key)
+                                    && !Arrays.asList(lastActiveTasks).contains(task)) {
+                                lastActiveTask = task;
+                                break;
+                            }
                         }
-                        Task task2 = groupTask.task2;
-                        if (isInstanceOfComponent(task2, key)
-                                && !Arrays.asList(lastActiveTasks).contains(task2)) {
-                            lastActiveTask = task2;
+                        if (lastActiveTask != null) {
                             break;
                         }
                     }
@@ -460,77 +453,41 @@
         Bundle optionsBundle = options1.toBundle();
         Bundle extrasBundle = new Bundle(1);
         extrasBundle.putParcelable(KEY_EXTRA_WIDGET_INTENT, widgetIntent);
-        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
-                    secondTaskId, callback, "LaunchSplitPair");
-            switch (launchData.getSplitLaunchType()) {
-                case SPLIT_TASK_TASK ->
-                        mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
-                                null /* options2 */, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+        final RemoteTransition remoteTransition = getRemoteTransition(firstTaskId,
+                secondTaskId, callback, "LaunchSplitPair");
+        switch (launchData.getSplitLaunchType()) {
+            case SPLIT_TASK_TASK ->
+                    mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
+                            null /* options2 */, initialStagePosition, snapPosition,
+                            remoteTransition, shellInstanceId);
 
-                case SPLIT_TASK_PENDINGINTENT ->
-                        mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
-                                firstTaskId, extrasBundle, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+            case SPLIT_TASK_PENDINGINTENT ->
+                    mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
+                            firstTaskId, extrasBundle, initialStagePosition, snapPosition,
+                            remoteTransition, shellInstanceId);
 
-                case SPLIT_TASK_SHORTCUT ->
-                        mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
-                                firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+            case SPLIT_TASK_SHORTCUT ->
+                    mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
+                            firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
+                            remoteTransition, shellInstanceId);
 
-                case SPLIT_PENDINGINTENT_TASK ->
-                        mSystemUiProxy.startIntentAndTask(firstPI, firstUserId, optionsBundle,
-                                secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+            case SPLIT_PENDINGINTENT_TASK ->
+                    mSystemUiProxy.startIntentAndTask(firstPI, firstUserId, optionsBundle,
+                            secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
+                            remoteTransition, shellInstanceId);
 
-                case SPLIT_PENDINGINTENT_PENDINGINTENT ->
-                        mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
-                                optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
-                                initialStagePosition, snapPosition, remoteTransition,
-                                shellInstanceId);
+            case SPLIT_PENDINGINTENT_PENDINGINTENT ->
+                    mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
+                            optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
+                            initialStagePosition, snapPosition, remoteTransition,
+                            shellInstanceId);
 
-                case SPLIT_SHORTCUT_TASK ->
-                        mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
-                                secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
-            }
-        } else {
-            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId, secondTaskId,
-                    callback);
-            switch (launchData.getSplitLaunchType()) {
-                case SPLIT_TASK_TASK ->
-                        mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
-                                secondTaskId, null /* options2 */, initialStagePosition,
-                                snapPosition, adapter, shellInstanceId);
-
-                case SPLIT_TASK_PENDINGINTENT ->
-                        mSystemUiProxy.startIntentAndTaskWithLegacyTransition(secondPI,
-                                secondUserId, optionsBundle, firstTaskId, null /*options2*/,
-                                initialStagePosition, snapPosition, adapter, shellInstanceId);
-
-                case SPLIT_TASK_SHORTCUT ->
-                        mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(secondShortcut,
-                                optionsBundle, firstTaskId, null /*options2*/, initialStagePosition,
-                                snapPosition, adapter, shellInstanceId);
-
-                case SPLIT_PENDINGINTENT_TASK ->
-                        mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
-                                optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, snapPosition, adapter, shellInstanceId);
-
-                case SPLIT_PENDINGINTENT_PENDINGINTENT ->
-                        mSystemUiProxy.startIntentsWithLegacyTransition(firstPI, firstUserId,
-                                firstShortcut, optionsBundle, secondPI, secondUserId,
-                                secondShortcut, null /*options2*/, initialStagePosition,
-                                snapPosition, adapter, shellInstanceId);
-
-                case SPLIT_SHORTCUT_TASK ->
-                        mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(firstShortcut,
-                                optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, snapPosition, adapter, shellInstanceId);
-            }
+            case SPLIT_SHORTCUT_TASK ->
+                    mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
+                            secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
+                            remoteTransition, shellInstanceId);
         }
+
     }
 
     /**
@@ -576,20 +533,13 @@
         }
         Bundle optionsBundle = options1.toBundle();
 
-        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteTransition transition = remoteTransition == null
-                    ? getShellRemoteTransition(
-                            firstTaskId, secondTaskId, callback, "LaunchExistingPair")
-                    : remoteTransition;
-            mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
-                    stagePosition, snapPosition, transition, null /*shellInstanceId*/);
-        } else {
-            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
-                    secondTaskId, callback);
-            mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle, secondTaskId,
-                    null /* options2 */, stagePosition, snapPosition, adapter,
-                    null /*shellInstanceId*/);
-        }
+        final RemoteTransition transition = remoteTransition == null
+                ? getRemoteTransition(
+                firstTaskId, secondTaskId, callback, "LaunchExistingPair")
+                : remoteTransition;
+        mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
+                stagePosition, snapPosition, transition, null /*shellInstanceId*/);
+
     }
 
     /**
@@ -615,34 +565,16 @@
                 ActivityThread.currentActivityThread().getApplicationThread(),
                 "LaunchAppFullscreen");
         InstanceId instanceId = mSessionInstanceIds.first;
-        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            switch (launchData.getSplitLaunchType()) {
-                case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
-                        optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
-                        SNAP_TO_50_50, remoteTransition, instanceId);
-                case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
-                        firstUserId, optionsBundle, secondTaskId, null /*options2*/,
-                        initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
-                case SPLIT_SINGLE_SHORTCUT_FULLSCREEN -> mSystemUiProxy.startShortcutAndTask(
-                        initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
-                        initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
-            }
-        } else {
-            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
-                    secondTaskId, callback);
-            switch (launchData.getSplitLaunchType()) {
-                case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasksWithLegacyTransition(
-                        firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
-                        initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
-                case SPLIT_SINGLE_INTENT_FULLSCREEN ->
-                        mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
-                                optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
-                case SPLIT_SINGLE_SHORTCUT_FULLSCREEN ->
-                        mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(
-                                initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
-                                initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
-            }
+        switch (launchData.getSplitLaunchType()) {
+            case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
+                    optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
+                    SNAP_TO_50_50, remoteTransition, instanceId);
+            case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
+                    firstUserId, optionsBundle, secondTaskId, null /*options2*/,
+                    initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
+            case SPLIT_SINGLE_SHORTCUT_FULLSCREEN -> mSystemUiProxy.startShortcutAndTask(
+                    initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
+                    initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
         }
     }
 
@@ -660,7 +592,7 @@
         mSplitFromDesktopController = controller;
     }
 
-    private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
+    private RemoteTransition getRemoteTransition(int firstTaskId, int secondTaskId,
             @Nullable Consumer<Boolean> callback, String transitionName) {
         final RemoteSplitLaunchTransitionRunner animationRunner =
                 new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
@@ -668,14 +600,6 @@
                 ActivityThread.currentActivityThread().getApplicationThread(), transitionName);
     }
 
-    private RemoteAnimationAdapter getLegacyRemoteAdapter(int firstTaskId, int secondTaskId,
-            @Nullable Consumer<Boolean> callback) {
-        final RemoteSplitLaunchAnimationRunner animationRunner =
-                new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
-        return new RemoteAnimationAdapter(animationRunner, 300, 150,
-                ActivityThread.currentActivityThread().getApplicationThread());
-    }
-
     /**
      * Will initialize {@link #mSessionInstanceIds} if null and log the first split event from
      * {@link #mSplitSelectDataHolder}
@@ -807,55 +731,6 @@
     }
 
     /**
-     * LEGACY
-     * Remote animation runner for animation to launch an app.
-     */
-    private class RemoteSplitLaunchAnimationRunner extends RemoteAnimationRunnerCompat {
-
-        private final int mInitialTaskId;
-        private final int mSecondTaskId;
-        private final Consumer<Boolean> mSuccessCallback;
-
-        RemoteSplitLaunchAnimationRunner(int initialTaskId, int secondTaskId,
-                @Nullable Consumer<Boolean> successCallback) {
-            mInitialTaskId = initialTaskId;
-            mSecondTaskId = secondTaskId;
-            mSuccessCallback = successCallback;
-        }
-
-        @Override
-        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
-                RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
-                Runnable finishedCallback) {
-            postAsyncCallback(mHandler,
-                    () -> mSplitAnimationController
-                            .playSplitLaunchAnimation(mLaunchingTaskView,
-                            mLaunchingIconView, mInitialTaskId, mSecondTaskId, apps, wallpapers,
-                            nonApps, mStateManager, mDepthController, null /* info */, null /* t */,
-                            () -> {
-                                finishedCallback.run();
-                                if (mSuccessCallback != null) {
-                                    mSuccessCallback.accept(true);
-                                }
-                                resetState();
-                            },
-                            QuickStepContract.getWindowCornerRadius(mContainer.asContext())));
-        }
-
-        @Override
-        public void onAnimationCancelled() {
-            postAsyncCallback(mHandler, () -> {
-                if (mSuccessCallback != null) {
-                    // Launching legacy tasks while recents animation is running will always cause
-                    // onAnimationCancelled to be called (should be fixed w/ shell transitions?)
-                    mSuccessCallback.accept(mRecentsAnimationRunning);
-                }
-                resetState();
-            });
-        }
-    }
-
-    /**
      * To be called whenever we exit split selection state. If
      * {@link FeatureFlags#enableSplitContextually()} is set, this should be the
      * central way split is getting reset, which should then go through the callbacks to reset
@@ -961,7 +836,7 @@
         private final int mSplitPlaceholderSize;
         private final int mSplitPlaceholderInset;
         private ActivityManager.RunningTaskInfo mTaskInfo;
-        private ISplitSelectListener mSplitSelectListener;
+        private DesktopSplitSelectListenerImpl mSplitSelectListener;
         private Drawable mAppIcon;
 
         public SplitFromDesktopController(QuickstepLauncher launcher,
@@ -972,21 +847,14 @@
                     R.dimen.split_placeholder_size);
             mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
                     R.dimen.split_placeholder_inset);
-            mSplitSelectListener = new ISplitSelectListener.Stub() {
-                @Override
-                public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
-                        int splitPosition, Rect taskBounds) {
-                    MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
-                            taskBounds));
-                    return true;
-                }
-            };
+            mSplitSelectListener = new DesktopSplitSelectListenerImpl(this);
             SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
         }
 
         void onDestroy() {
             SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener(
                     mSplitSelectListener);
+            mSplitSelectListener.release();
             mSplitSelectListener = null;
         }
 
@@ -1079,4 +947,35 @@
             }
         }
     }
+
+    /**
+     * Wrapper for the ISplitSelectListener stub to prevent lingering references to the launcher
+     * activity via the controller.
+     */
+    private static class DesktopSplitSelectListenerImpl extends ISplitSelectListener.Stub {
+
+        private SplitFromDesktopController mController;
+
+        DesktopSplitSelectListenerImpl(@NonNull SplitFromDesktopController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Clears any references to the controller.
+         */
+        void release() {
+            mController = null;
+        }
+
+        @Override
+        public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
+                int splitPosition, Rect taskBounds) {
+            MAIN_EXECUTOR.execute(() -> {
+                if (mController != null) {
+                    mController.enterSplitSelect(taskInfo, splitPosition, taskBounds);
+                }
+            });
+            return true;
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index d9b7d20..e5c54bb 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -171,7 +171,6 @@
             mTaskRect.set(mFullTaskSize);
             mOrientationState.getOrientationHandler()
                     .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
         } else if (mIsDesktopTask) {
             // For desktop, tasks can take up only part of the screen size.
             // Full task size represents the whole screen size, but scaled down to fit in recents.
@@ -185,10 +184,19 @@
             mTaskRect.scale(scale);
             // Ensure the task rect is inside the full task rect
             mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
+
+            Rect taskDimension = new Rect(0, 0, (int) fullscreenTaskDimension.x,
+                    (int) fullscreenTaskDimension.y);
+            mTmpCropRect.set(mThumbnailPosition);
+            if (mTmpCropRect.setIntersect(taskDimension, mThumbnailPosition)) {
+                mTmpCropRect.offset(-mThumbnailPosition.left, -mThumbnailPosition.top);
+            } else {
+                mTmpCropRect.setEmpty();
+            }
         } else {
             mTaskRect.set(mFullTaskSize);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
         }
+        mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
     }
 
     /**
@@ -486,10 +494,12 @@
                 recentsViewPrimaryTranslation.value);
         applyWindowToHomeRotation(mMatrix);
 
-        // Crop rect is the inverse of thumbnail matrix
-        mTempRectF.set(0, 0, taskWidth, taskHeight);
-        mInversePositionMatrix.mapRect(mTempRectF);
-        mTempRectF.roundOut(mTmpCropRect);
+        if (!mIsDesktopTask) {
+            // Crop rect is the inverse of thumbnail matrix
+            mTempRectF.set(0, 0, taskWidth, taskHeight);
+            mInversePositionMatrix.mapRect(mTempRectF);
+            mTempRectF.roundOut(mTmpCropRect);
+        }
 
         params.setProgress(1f - fullScreenProgress);
         params.applySurfaceParams(surfaceTransaction == null
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 9ce2277..8e48f22 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -19,7 +19,6 @@
 import android.graphics.Point
 import android.graphics.PointF
 import android.graphics.Rect
-import android.graphics.drawable.LayerDrawable
 import android.graphics.drawable.ShapeDrawable
 import android.graphics.drawable.shapes.RoundRectShape
 import android.util.AttributeSet
@@ -27,9 +26,12 @@
 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
 import com.android.launcher3.R
+import com.android.launcher3.testing.TestLogging
+import com.android.launcher3.testing.shared.TestProtocol
 import com.android.launcher3.util.RunnableList
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TransformingTouchDelegate
@@ -84,9 +86,15 @@
             }
         iconView =
             getOrInflateIconView(R.id.icon).apply {
-                val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme)
-                val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme)
-                setIcon(this, LayerDrawable(arrayOf(iconBackground, icon)))
+                setIcon(
+                    this,
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.ic_desktop_with_bg,
+                        context.theme
+                    )
+                )
+                setText(resources.getText(R.string.recent_task_desktop))
             }
         childCountAtInflation = childCount
     }
@@ -213,7 +221,15 @@
     }
 
     override fun needsUpdate(dataChange: Int, flag: Int) =
-        if (flag == FLAG_UPDATE_THUMBNAIL) super.needsUpdate(dataChange, flag) else false
+        if (flag == FLAG_UPDATE_CORNER_RADIUS) false else super.needsUpdate(dataChange, flag)
+
+    override fun onIconLoaded(taskContainer: TaskContainer) {
+        // Update contentDescription of snapshotView only, individual task icon is unused.
+        taskContainer.snapshotView.contentDescription = taskContainer.task.titleDescription
+    }
+
+    // Ignoring [onIconUnloaded] as all tasks shares the same Desktop icon
+    override fun onIconUnloaded(taskContainer: TaskContainer) {}
 
     // thumbnailView is laid out differently and is handled in onMeasure
     override fun updateThumbnailSize() {}
@@ -226,22 +242,33 @@
         }
     }
 
-    override fun launchTaskAnimated(): RunnableList? {
+    private fun launchTaskWithDesktopController(animated: Boolean): RunnableList? {
         val recentsView = recentsView ?: return null
+        TestLogging.recordEvent(
+            TestProtocol.SEQUENCE_MAIN,
+            "launchDesktopFromRecents",
+            taskIds.contentToString()
+        )
         val endCallback = RunnableList()
         val desktopController = recentsView.desktopRecentsController
         checkNotNull(desktopController) { "recentsController is null" }
-        desktopController.launchDesktopFromRecents(this) { endCallback.executeAllAndDestroy() }
-        Log.d(TAG, "launchTaskAnimated - launchDesktopFromRecents: ${taskIds.contentToString()}")
+        desktopController.launchDesktopFromRecents(this, animated) {
+            endCallback.executeAllAndDestroy()
+        }
+        Log.d(
+            TAG,
+            "launchTaskAnimated - launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
+        )
 
         // Callbacks get run from recentsView for case when recents animation already running
         recentsView.addSideTaskLaunchCallback(endCallback)
         return endCallback
     }
 
+    override fun launchTaskAnimated() = launchTaskWithDesktopController(animated = true)
+
     override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
-        launchTasks()
-        callback(true)
+        launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
     }
 
     // Desktop tile can't be in split screen
@@ -251,8 +278,7 @@
     override fun setOverlayEnabled(overlayEnabled: Boolean) {}
 
     override fun onFullscreenProgressChanged(fullscreenProgress: Float) {
-        // Don't show background while we are transitioning to/from fullscreen
-        backgroundView.visibility = if (fullscreenProgress > 0) INVISIBLE else VISIBLE
+        backgroundView.alpha = 1 - fullscreenProgress
     }
 
     override fun updateCurrentFullscreenParams() {
@@ -266,6 +292,7 @@
         private const val TAG = "DesktopTaskView"
         private const val DEBUG = false
         private const val VIEW_POOL_MAX_SIZE = 10
+
         // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
         private const val VIEW_POOL_INITIAL_SIZE = 0
         private val ORIGIN = Point(0, 0)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8b6bc39..53e6e72 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -40,6 +40,7 @@
 import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
@@ -57,6 +58,7 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
+import static com.android.quickstep.BaseContainerInterface.getTaskDimension;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
 import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN;
@@ -90,6 +92,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -135,6 +138,7 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.PagedView;
@@ -553,6 +557,7 @@
     // Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
     private float mGridProgress = 0;
     private float mTaskThumbnailSplashAlpha = 0;
+    private boolean mBorderEnabled = false;
     private boolean mShowAsGridLastOnLayout = false;
     private final IntSet mTopRowIdSet = new IntSet();
     private int mClearAllShortTotalWidthTranslation = 0;
@@ -1047,8 +1052,11 @@
     @Override
     @Nullable
     public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
+        if (enableRefactorTaskThumbnail()) {
+            mHelper.onTaskThumbnailChanged(taskId, thumbnailData);
+            return null;
+        }
         if (mHandleTaskStackChanges) {
-            // TODO(b/342560598): Handle onTaskThumbnailChanged for new TTV.
             if (!enableRefactorTaskThumbnail()) {
                 TaskView taskView = getTaskViewByTaskId(taskId);
                 if (taskView != null) {
@@ -1067,6 +1075,7 @@
 
     @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();
@@ -1082,47 +1091,36 @@
 
     @Override
     public void onTaskIconChanged(int taskId) {
+        if (enableRefactorTaskThumbnail()) {
+            return;
+        }
         TaskView taskView = getTaskViewByTaskId(taskId);
         if (taskView != null) {
             taskView.refreshTaskThumbnailSplash();
         }
     }
 
-    /**
-     * Update the thumbnail(s) of the relevant TaskView.
-     *
-     * @param refreshNow Refresh immediately if it's true.
-     */
-    @Nullable
-    public TaskView updateThumbnail(
-            HashMap<Integer, ThumbnailData> thumbnailData, boolean refreshNow) {
-        if (enableRefactorTaskThumbnail()) {
-            // TODO(b/342560598): Handle updateThumbnail for new TTV.
-            return null;
-        }
-        TaskView updatedTaskView = null;
-        for (Map.Entry<Integer, ThumbnailData> entry : thumbnailData.entrySet()) {
-            Integer id = entry.getKey();
-            ThumbnailData thumbnail = entry.getValue();
-            TaskView taskView = getTaskViewByTaskId(id);
-            if (taskView == null) {
-                continue;
+    /** Updates the thumbnail(s) of the relevant TaskView. */
+    public void updateThumbnail(Map<Integer, ThumbnailData> thumbnailData) {
+        if (!enableRefactorTaskThumbnail()) {
+            for (Map.Entry<Integer, ThumbnailData> entry : thumbnailData.entrySet()) {
+                Integer id = entry.getKey();
+                ThumbnailData thumbnail = entry.getValue();
+                TaskView taskView = getTaskViewByTaskId(id);
+                if (taskView == null) {
+                    continue;
+                }
+                // taskView could be a GroupedTaskView, so select the relevant task by ID
+                TaskContainer taskContainer = taskView.getTaskContainerById(id);
+                if (taskContainer == null) {
+                    continue;
+                }
+                Task task = taskContainer.getTask();
+                TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
+                        taskContainer.getThumbnailViewDeprecated();
+                taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, /*refreshNow=*/false);
             }
-            // taskView could be a GroupedTaskView, so select the relevant task by ID
-            TaskContainer taskAttributes = taskView.getTaskContainerById(id);
-            if (taskAttributes == null) {
-                continue;
-            }
-            Task task = taskAttributes.getTask();
-            TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
-                    taskAttributes.getThumbnailViewDeprecated();
-            taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, refreshNow);
-            // thumbnailData can contain 1-2 ids, but they should correspond to the same
-            // TaskView, so overwriting is ok
-            updatedTaskView = taskView;
         }
-
-        return updatedTaskView;
     }
 
     @Override
@@ -1532,6 +1530,7 @@
      * Enable or disable showing border on hover and focus change on task views
      */
     public void setTaskBorderEnabled(boolean enabled) {
+        mBorderEnabled = enabled;
         int taskCount = getTaskViewCount();
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
@@ -2051,6 +2050,7 @@
                 taskView.setFullscreenProgress(mFullscreenProgress);
                 taskView.setModalness(mTaskModalness);
                 taskView.setTaskThumbnailSplashAlpha(mTaskThumbnailSplashAlpha);
+                taskView.setBorderEnabled(mBorderEnabled);
             }
         }
         // resetTaskVisuals is called at the end of dismiss animation which could update
@@ -2440,10 +2440,6 @@
                 List<Task> tasksToUpdate = containers.stream()
                         .map(TaskContainer::getTask)
                         .collect(Collectors.toCollection(ArrayList::new));
-                if (enableRefactorTaskThumbnail()) {
-                    visibleTaskIds.addAll(
-                            tasksToUpdate.stream().map((task) -> task.key.id).toList());
-                }
                 if (mTmpRunningTasks != null) {
                     for (Task t : mTmpRunningTasks) {
                         // Skip loading if this is the task that we are animating into
@@ -2451,6 +2447,10 @@
                         tasksToUpdate.removeIf(task -> task == t);
                     }
                 }
+                if (enableRefactorTaskThumbnail()) {
+                    visibleTaskIds.addAll(
+                            tasksToUpdate.stream().map((task) -> task.key.id).toList());
+                }
                 if (tasksToUpdate.isEmpty()) {
                     continue;
                 }
@@ -2507,6 +2507,11 @@
             mModel.preloadCacheIfNeeded();
         }
 
+        if (enableRefactorTaskThumbnail()) {
+            // TODO(b/342560598): Listen in TaskRepository and reload.
+            return;
+        }
+
         // Whenever the high res loading state changes, poke each of the visible tasks to see if
         // they want to updated their thumbnail state
         for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
@@ -4919,6 +4924,9 @@
                 mSplitHiddenTaskView.updateSnapshotRadius();
             });
         } else if (isInitiatingSplitFromTaskView) {
+            if (Flags.enableHoverOfChildElementsInTaskview()) {
+                mSplitHiddenTaskView.setBorderEnabled(false);
+            }
             // Splitting from Overview for fullscreen task
             createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration,
                     true /* dismissingForSplitSelection*/);
@@ -5227,23 +5235,37 @@
      * to the right.
      */
     @SuppressLint("Recycle")
-    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView taskView) {
         AnimatorSet anim = new AnimatorSet();
 
-        int taskIndex = indexOfChild(tv);
+        int taskIndex = indexOfChild(taskView);
         int centerTaskIndex = getCurrentPage();
 
         float toScale = getMaxScaleForFullScreen();
         boolean showAsGrid = showAsGrid();
-        boolean launchingCenterTask = showAsGrid
-                ? tv.isFocusedTask() && isTaskViewFullyVisible(tv)
+        boolean zoomInTaskView = showAsGrid
+                ? ((taskView.isFocusedTask() && isTaskViewFullyVisible(taskView))
+                || taskView instanceof DesktopTaskView)
                 : taskIndex == centerTaskIndex;
-        if (launchingCenterTask) {
+        if (zoomInTaskView) {
             anim.play(ObjectAnimator.ofFloat(this, RECENTS_SCALE_PROPERTY, toScale));
             anim.play(ObjectAnimator.ofFloat(this, FULLSCREEN_PROGRESS, 1));
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
+                    taskView.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+                    getTaskDimension(mContext, mContainer.getDeviceProfile(), mTempPointF);
+                    Rect fullscreenBounds = new Rect(0, 0, (int) mTempPointF.x,
+                            (int) mTempPointF.y);
+                    Utilities.getPivotsForScalingRectToRect(mTempRect, fullscreenBounds,
+                            mTempPointF);
+                    setPivotX(mTempPointF.x);
+                    setPivotY(mTempPointF.y);
+                }
+            });
         } else if (!showAsGrid) {
             // We are launching an adjacent task, so parallax the center and other adjacent task.
-            float displacementX = tv.getWidth() * (toScale - 1f);
+            float displacementX = taskView.getWidth() * (toScale - 1f);
             float primaryTranslation = mIsRtl ? -displacementX : displacementX;
             anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
                     getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation));
@@ -5271,6 +5293,17 @@
             }
         }
         anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0, 1));
+        if (taskView instanceof DesktopTaskView) {
+            anim.play(ObjectAnimator.ofArgb(mContainer.getScrimView(), VIEW_BACKGROUND_COLOR,
+                    Color.TRANSPARENT));
+        }
+        DepthController depthController = getDepthController();
+        if (depthController != null) {
+            float targetDepth = taskView instanceof DesktopTaskView ? 0 : BACKGROUND_APP.getDepth(
+                    mContainer);
+            anim.play(ObjectAnimator.ofFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE,
+                    targetDepth));
+        }
         return anim;
     }
 
@@ -5296,7 +5329,7 @@
     }
 
     public PendingAnimation createTaskLaunchAnimation(
-            TaskView tv, long duration, Interpolator interpolator) {
+            TaskView taskView, long duration, Interpolator interpolator) {
         if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
             throw new IllegalStateException("Another pending animation is still running");
         }
@@ -5311,13 +5344,13 @@
         updateGridProperties();
         updateScrollSynchronously();
 
-        int targetSysUiFlags = tv.getTaskContainers().getFirst().getSysUiStatusNavFlags();
+        int targetSysUiFlags = taskView.getTaskContainers().getFirst().getSysUiStatusNavFlags();
         final boolean[] passedOverviewThreshold = new boolean[]{false};
-        ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
-        progressAnim.addUpdateListener(animator -> {
+        AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(taskView);
+        anim.play(new AnimatedFloat(v -> {
             // Once we pass a certain threshold, update the sysui flags to match the target
             // tasks' flags
-            if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+            if (v > UPDATE_SYSUI_FLAGS_THRESHOLD) {
                 mContainer.getSystemUiController().updateUiState(
                         UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
             } else {
@@ -5325,8 +5358,7 @@
             }
 
             // Passing the threshold from taskview to fullscreen app will vibrate
-            final boolean passed = animator.getAnimatedFraction() >=
-                    SUCCESS_TRANSITION_PROGRESS;
+            final boolean passed = v >= SUCCESS_TRANSITION_PROGRESS;
             if (passed != passedOverviewThreshold[0]) {
                 passedOverviewThreshold[0] = passed;
                 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -5336,19 +5368,7 @@
                     mRecentsAnimationController.setWillFinishToHome(!passed);
                 }
             }
-        });
-
-        AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
-
-        DepthController depthController = getDepthController();
-        if (depthController != null) {
-            ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth,
-                    MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mContainer));
-            anim.play(depthAnimator);
-        }
-        anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f));
-
-        anim.play(progressAnim);
+        }).animateToValue(0f, 1f));
         anim.setInterpolator(interpolator);
 
         mPendingAnimation = new PendingAnimation(duration);
@@ -5357,9 +5377,18 @@
                 remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
                         .addOverviewToAppAnim(mPendingAnimation, interpolator));
         mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
+        if (taskView instanceof DesktopTaskView && mRemoteTargetHandles != null) {
+            mPendingAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    runActionOnRemoteHandles(remoteTargetHandle ->
+                            remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
+                }
+            });
+        }
         mPendingAnimation.addEndListener(isSuccess -> {
             if (isSuccess) {
-                if (tv instanceof GroupedTaskView && hasAllValidTaskIds(tv.getTaskIds())
+                if (taskView instanceof GroupedTaskView && hasAllValidTaskIds(taskView.getTaskIds())
                         && mRemoteTargetHandles != null) {
                     // TODO(b/194414938): make this part of the animations instead.
                     TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
@@ -5369,13 +5398,13 @@
                                 dividerAnimator.end();
                             });
                 }
-                if (tv.isRunningTask()) {
+                if (taskView.isRunningTask()) {
                     finishRecentsAnimation(false /* toRecents */, null);
                     onTaskLaunchAnimationEnd(true /* success */);
                 } else {
-                    tv.launchTask(this::onTaskLaunchAnimationEnd);
+                    taskView.launchTask(this::onTaskLaunchAnimationEnd);
                 }
-                mContainer.getStatsLogManager().logger().withItemInfo(tv.getFirstItemInfo())
+                mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo())
                         .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
             } else {
                 onTaskLaunchAnimationEnd(false);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
index 05c2462..e8c9718 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
@@ -60,9 +60,6 @@
         // Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
         // viewAttachedScope.
         recentsViewModel.setRunningTaskShowScreenshot(true)
-        if (updatedThumbnails != null) {
-            recentsViewModel.setThumbnailOverride(updatedThumbnails)
-        }
         viewAttachedScope.launch {
             recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
             if (updatedThumbnails != null) {
@@ -71,4 +68,8 @@
             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/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index e10d38c..158ae33 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -42,7 +42,11 @@
     companion object {
         const val TAG = "TaskMenuViewWithArrow"
 
-        fun showForTask(taskContainer: TaskContainer, alignedOptionIndex: Int = 0): Boolean {
+        fun showForTask(
+            taskContainer: TaskContainer,
+            alignedOptionIndex: Int = 0,
+            onClosedCallback: Runnable? = null
+        ): Boolean {
             val container: RecentsViewContainer =
                 RecentsViewContainer.containerFromContext(taskContainer.taskView.context)
             val taskMenuViewWithArrow =
@@ -52,7 +56,11 @@
                     false
                 ) as TaskMenuViewWithArrow<*>
 
-            return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignedOptionIndex)
+            return taskMenuViewWithArrow.populateAndShowForTask(
+                taskContainer,
+                alignedOptionIndex,
+                onClosedCallback
+            )
         }
     }
 
@@ -98,6 +106,7 @@
     private var iconView: IconView? = null
     private var scrim: View? = null
     private val scrimAlpha = 0.8f
+    private var onClosedCallback: Runnable? = null
 
     override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
 
@@ -141,7 +150,8 @@
 
     private fun populateAndShowForTask(
         taskContainer: TaskContainer,
-        alignedOptionIndex: Int
+        alignedOptionIndex: Int,
+        onClosedCallback: Runnable?
     ): Boolean {
         if (isAttachedToWindow) {
             return false
@@ -150,6 +160,7 @@
         taskView = taskContainer.taskView
         this.taskContainer = taskContainer
         this.alignedOptionIndex = alignedOptionIndex
+        this.onClosedCallback = onClosedCallback
         if (!populateMenu()) return false
         addScrim()
         show()
@@ -252,6 +263,7 @@
         super.closeComplete()
         popupContainer.removeView(scrim)
         popupContainer.removeView(iconView)
+        onClosedCallback?.run()
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 292595c..176a538 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -48,6 +48,7 @@
 import com.android.launcher3.Flags.enableCursorHoverStates
 import com.android.launcher3.Flags.enableFocusOutline
 import com.android.launcher3.Flags.enableGridOnlyOverview
+import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview
 import com.android.launcher3.Flags.enableOverviewIconMenu
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.R
@@ -413,6 +414,26 @@
             focusBorderAnimator?.setBorderVisibility(visible = field && isFocused, animated = true)
         }
 
+    /**
+     * Used to cache the hover border state so we don't repeatedly call the border animator with
+     * every hover event when the user hasn't crossed the threshold of the [thumbnailBounds].
+     */
+    private var hoverBorderVisible = false
+        set(value) {
+            if (field == value) {
+                return
+            }
+            field = value
+            Log.d(
+                TAG,
+                "${taskIds.contentToString()} - setting border animator visibility to: $field"
+            )
+            hoverBorderAnimator?.setBorderVisibility(visible = field, animated = true)
+        }
+
+    // Used to cache thumbnail bounds to avoid recalculating on every hover move.
+    private var thumbnailBounds = Rect()
+
     private var focusTransitionProgress = 1f
         set(value) {
             field = value
@@ -511,20 +532,28 @@
     override fun onHoverEvent(event: MotionEvent): Boolean {
         if (borderEnabled) {
             when (event.action) {
-                MotionEvent.ACTION_HOVER_ENTER ->
-                    hoverBorderAnimator?.setBorderVisibility(visible = true, animated = true)
-                MotionEvent.ACTION_HOVER_EXIT ->
-                    hoverBorderAnimator?.setBorderVisibility(visible = false, animated = true)
+                MotionEvent.ACTION_HOVER_ENTER -> {
+                    hoverBorderVisible =
+                        if (enableHoverOfChildElementsInTaskview()) {
+                            getThumbnailBounds(thumbnailBounds)
+                            event.isWithinThumbnailBounds()
+                        } else {
+                            true
+                        }
+                }
+                MotionEvent.ACTION_HOVER_MOVE ->
+                    if (enableHoverOfChildElementsInTaskview())
+                        hoverBorderVisible = event.isWithinThumbnailBounds()
+                MotionEvent.ACTION_HOVER_EXIT -> hoverBorderVisible = false
                 else -> {}
             }
         }
         return super.onHoverEvent(event)
     }
 
-    // avoid triggering hover event on child elements which would cause HOVER_EXIT for this
-    // task view
-    override fun onInterceptHoverEvent(event: MotionEvent) =
-        if (enableCursorHoverStates()) true else super.onInterceptHoverEvent(event)
+    override fun onInterceptHoverEvent(event: MotionEvent): Boolean =
+        if (enableHoverOfChildElementsInTaskview()) super.onInterceptHoverEvent(event)
+        else if (enableCursorHoverStates()) true else super.onInterceptHoverEvent(event)
 
     override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
         val recentsView = recentsView ?: return false
@@ -567,6 +596,9 @@
                 it.right = width
                 it.bottom = height
             }
+        if (enableHoverOfChildElementsInTaskview()) {
+            getThumbnailBounds(thumbnailBounds)
+        }
     }
 
     override fun onRecycle() {
@@ -579,6 +611,7 @@
         setOverlayEnabled(false)
         onTaskListVisibilityChanged(false)
         borderEnabled = false
+        hoverBorderVisible = false
         taskViewId = UNBOUND_TASK_VIEW_ID
         taskContainers.forEach { it.destroy() }
     }
@@ -868,18 +901,11 @@
                             it.task.icon = icon
                             it.task.titleDescription = contentDescription
                             it.task.title = title
-                            setIcon(it.iconView, icon)
-                            if (enableOverviewIconMenu()) {
-                                setText(it.iconView, title)
-                            }
-                            it.digitalWellBeingToast?.initialize(it.task)
+                            onIconLoaded(it)
                         }
                         ?.also { request -> pendingIconLoadRequests.add(request) }
                 } else {
-                    setIcon(it.iconView, null)
-                    if (enableOverviewIconMenu()) {
-                        setText(it.iconView, null)
-                    }
+                    onIconUnloaded(it)
                 }
             }
         }
@@ -898,6 +924,21 @@
         pendingIconLoadRequests.clear()
     }
 
+    protected open fun onIconLoaded(taskContainer: TaskContainer) {
+        setIcon(taskContainer.iconView, taskContainer.task.icon)
+        if (enableOverviewIconMenu()) {
+            setText(taskContainer.iconView, taskContainer.task.title)
+        }
+        taskContainer.digitalWellBeingToast?.initialize(taskContainer.task)
+    }
+
+    protected open fun onIconUnloaded(taskContainer: TaskContainer) {
+        setIcon(taskContainer.iconView, null)
+        if (enableOverviewIconMenu()) {
+            setText(taskContainer.iconView, null)
+        }
+    }
+
     protected fun setIcon(iconView: TaskViewIcon, icon: Drawable?) {
         with(iconView) {
             if (icon != null) {
@@ -1119,6 +1160,11 @@
             isClickableAsLiveTile = true
             return runnableList
         }
+        TestLogging.recordEvent(
+            TestProtocol.SEQUENCE_MAIN,
+            "composeRecentsLaunchAnimator",
+            taskIds.contentToString()
+        )
         val runnableList = RunnableList()
         with(AnimatorSet()) {
             TaskViewUtils.composeRecentsLaunchAnimator(
@@ -1225,10 +1271,17 @@
 
     private fun showTaskMenuWithContainer(menuContainer: TaskContainer): Boolean {
         val recentsView = recentsView ?: return false
+        if (enableHoverOfChildElementsInTaskview()) {
+            // Disable hover on all TaskView's whilst menu is showing.
+            recentsView.setTaskBorderEnabled(false)
+        }
         return if (enableOverviewIconMenu() && menuContainer.iconView is IconAppChipView) {
             menuContainer.iconView.revealAnim(/* isRevealing= */ true)
             TaskMenuView.showForTask(menuContainer) {
                 menuContainer.iconView.revealAnim(/* isRevealing= */ false)
+                if (enableHoverOfChildElementsInTaskview()) {
+                    recentsView.setTaskBorderEnabled(true)
+                }
             }
         } else if (container.deviceProfile.isTablet) {
             val alignedOptionIndex =
@@ -1248,9 +1301,17 @@
                 } else {
                     0
                 }
-            TaskMenuViewWithArrow.showForTask(menuContainer, alignedOptionIndex)
+            TaskMenuViewWithArrow.showForTask(menuContainer, alignedOptionIndex) {
+                if (enableHoverOfChildElementsInTaskview()) {
+                    recentsView.setTaskBorderEnabled(true)
+                }
+            }
         } else {
-            TaskMenuView.showForTask(menuContainer)
+            TaskMenuView.showForTask(menuContainer) {
+                if (enableHoverOfChildElementsInTaskview()) {
+                    recentsView.setTaskBorderEnabled(true)
+                }
+            }
         }
     }
 
@@ -1398,7 +1459,6 @@
 
     protected open fun refreshTaskThumbnailSplash() {
         if (!enableRefactorTaskThumbnail()) {
-            // TODO(b/342560598) handle onTaskIconChanged
             taskContainers.forEach { it.thumbnailViewDeprecated.refreshSplashView() }
         }
     }
@@ -1584,6 +1644,10 @@
         override fun close() {}
     }
 
+    private fun MotionEvent.isWithinThumbnailBounds(): Boolean {
+        return thumbnailBounds.contains(x.toInt(), y.toInt())
+    }
+
     companion object {
         private const val TAG = "TaskView"
         const val FLAG_UPDATE_ICON = 1
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
new file mode 100644
index 0000000..3e0d6b5
--- /dev/null
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.PathParser
+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.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.ViewScreenshotTestRule
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+/** Screenshot tests for [BubbleView]. */
+@RunWith(ParameterizedAndroidJunit4::class)
+class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun getTestSpecs() =
+            DeviceEmulationSpec.forDisplays(
+                Displays.Phone,
+                isDarkTheme = false,
+                isLandscape = false
+            )
+    }
+
+    @get:Rule
+    val screenshotRule =
+        ViewScreenshotTestRule(
+            emulationSpec,
+            ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec))
+        )
+
+    @Test
+    fun bubbleView_hasUnseenContent() {
+        screenshotRule.screenshotTest("bubbleView_hasUnseenContent") { activity ->
+            activity.actionBar?.hide()
+            setupBubbleView()
+        }
+    }
+
+    @Test
+    fun bubbleView_seen() {
+        screenshotRule.screenshotTest("bubbleView_seen") { activity ->
+            activity.actionBar?.hide()
+            setupBubbleView().apply { markSeen() }
+        }
+    }
+
+    @Test
+    fun bubbleView_badgeHidden() {
+        screenshotRule.screenshotTest("bubbleView_badgeHidden") { activity ->
+            activity.actionBar?.hide()
+            setupBubbleView().apply { setBadgeScale(0f) }
+        }
+    }
+
+    private fun setupBubbleView(): BubbleView {
+        val inflater = LayoutInflater.from(context)
+
+        val iconSize = 100
+        // BubbleView uses launcher's badge to icon ratio and expects the badge image to already
+        // have the right size
+        val badgeToIconRatio = 0.444f
+        val badgeRadius = iconSize * badgeToIconRatio / 2
+        val icon = createCircleBitmap(radius = iconSize / 2, color = Color.LTGRAY)
+        val badge = createCircleBitmap(radius = badgeRadius.toInt(), color = Color.RED)
+
+        val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+        val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null) as BubbleView
+        val dotPath =
+            PathParser.createPathFromPathData(
+                context.resources.getString(com.android.internal.R.string.config_icon_mask)
+            )
+        val bubble =
+            BubbleBarBubble(bubbleInfo, bubbleView, badge, icon, Color.BLUE, dotPath, "test app")
+        bubbleView.setBubble(bubble)
+        bubbleView.showDotIfNeeded(1f)
+        return bubbleView
+    }
+
+    private fun createCircleBitmap(radius: Int, color: Int): Bitmap {
+        val bitmap = Bitmap.createBitmap(radius * 2, radius * 2, Bitmap.Config.ARGB_8888)
+        val canvas = Canvas(bitmap)
+        canvas.drawARGB(0, 0, 0, 0)
+        val paint = Paint()
+        paint.color = color
+        canvas.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), paint)
+        return bitmap
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
index e583f63..961d4dc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.taskbar
+package com.android.launcher3.taskbar.test
 
+import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.Utilities
+import com.android.launcher3.taskbar.TOOLTIP_STEP_FEATURES
+import com.android.launcher3.taskbar.TOOLTIP_STEP_NONE
+import com.android.launcher3.taskbar.TOOLTIP_STEP_PINNING
+import com.android.launcher3.taskbar.TOOLTIP_STEP_SWIPE
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.TaskbarEduTooltipController
 import com.android.launcher3.taskbar.rules.TaskbarModeRule
 import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
 import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.THREE_BUTTONS
@@ -35,12 +42,14 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(LauncherMultivalentJUnit::class)
 @EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+@Ignore
 class TaskbarEduTooltipControllerTest {
 
     private val context =
@@ -48,25 +57,25 @@
             InstrumentationRegistry.getInstrumentation().targetContext
         )
 
-    @get:Rule
+    @get:Rule(order = 0)
     val tooltipStepPreferenceRule =
         TaskbarPreferenceRule(
             context,
             OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.prefItem,
         )
 
-    @get:Rule
+    @get:Rule(order = 1)
     val searchEduPreferenceRule =
         TaskbarPreferenceRule(
             context,
             OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN,
         )
 
-    @get:Rule val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
+    @get:Rule(order = 2) val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
 
-    @get:Rule val taskbarModeRule = TaskbarModeRule(context)
+    @get:Rule(order = 3) val taskbarModeRule = TaskbarModeRule(context)
 
-    @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+    @get:Rule(order = 4) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
 
     @InjectController lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
 
@@ -77,6 +86,7 @@
 
     @Before
     fun setUp() {
+        Log.e("Taskbar", "TaskbarEduTooltipControllerTest test started")
         Utilities.disableRunningInTestHarnessForTests()
     }
 
@@ -85,6 +95,7 @@
         if (wasInTestHarness) {
             Utilities.enableRunningInTestHarnessForTests()
         }
+        Log.e("Taskbar", "TaskbarEduTooltipControllerTest test completed")
     }
 
     @Test
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 e9c0dd6..4da06e1 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
@@ -35,8 +35,8 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
 import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
-import com.android.launcher3.taskbar.bubbles.BubbleStashController
 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
@@ -78,13 +78,13 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
         }
 
         // let the animation start and wait for it to complete
@@ -98,7 +98,7 @@
         assertThat(bubbleBarView.scaleX).isEqualTo(1)
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
 
         // execute the hide bubble animation
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -111,7 +111,7 @@
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).stashBubbleBarImmediate()
     }
 
@@ -122,13 +122,13 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
         }
 
         // let the animation start and wait for it to complete
@@ -142,7 +142,7 @@
         assertThat(bubbleBarView.scaleX).isEqualTo(1)
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
 
         verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
 
@@ -155,7 +155,7 @@
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
     }
 
     @Test
@@ -165,13 +165,13 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
         }
 
         // wait for the animation to start
@@ -179,7 +179,7 @@
         PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
 
         handleAnimator.assertIsRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
         // verify the hide bubble animation is pending
         assertThat(animatorScheduler.delayedBlock).isNotNull()
 
@@ -189,7 +189,7 @@
 
         // verify that the hide animation was canceled
         assertThat(animatorScheduler.delayedBlock).isNull()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
 
         // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
@@ -205,13 +205,13 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
         }
 
         // let the animation start and wait for it to complete
@@ -230,7 +230,7 @@
             animator.onStashStateChangingWhileAnimating()
         }
 
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
 
         // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
@@ -246,13 +246,13 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val animator =
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
         }
 
         // wait for the animation to start
@@ -260,16 +260,133 @@
         PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
 
         handleAnimator.assertIsRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
         assertThat(animatorScheduler.delayedBlock).isNotNull()
 
         handleAnimator.cancel()
         handleAnimator.assertIsNotRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         assertThat(animatorScheduler.delayedBlock).isNull()
     }
 
     @Test
+    fun animateBubbleInForStashed_autoExpanding() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble, isExpanding = true)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(handle.alpha).isEqualTo(0)
+        assertThat(handle.translationY)
+            .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+        assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleBarView.scaleX).isEqualTo(1)
+        assertThat(bubbleBarView.scaleY).isEqualTo(1)
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+        assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarView.isExpanded).isTrue()
+
+        // verify there is no hide animation
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_expandedWhileAnimatingIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+        handleAnimator.assertIsRunning()
+        assertThat(animator.isAnimating).isTrue()
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // let the animation finish
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        assertThat(handle.alpha).isEqualTo(0)
+        assertThat(handle.translationY)
+            .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+        verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
+        assertThat(animator.isAnimating).isFalse()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_expandedWhileFullyIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble, isExpanding = false)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        // wait for the animation to end
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(animator.isAnimating).isTrue()
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        assertThat(handle.alpha).isEqualTo(0)
+        assertThat(handle.translationY)
+            .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+        verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
+        assertThat(animator.isAnimating).isFalse()
+    }
+
+    @Test
     fun animateToInitialState_inApp() {
         setUpBubbleBar()
         setUpBubbleStashController()
@@ -278,7 +395,7 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
@@ -293,7 +410,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         barAnimator.assertIsNotRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
 
@@ -304,7 +421,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(0)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(handle.alpha).isEqualTo(1)
@@ -321,7 +438,7 @@
 
         val handle = View(context)
         val handleAnimator = PhysicsAnimator.getInstance(handle)
-        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+        whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
 
         val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
 
@@ -336,17 +453,11 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         barAnimator.assertIsNotRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
 
-        assertThat(animatorScheduler.delayedBlock).isNotNull()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
-
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
-        assertThat(bubbleBarView.alpha).isEqualTo(1)
-        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-
+        assertThat(animatorScheduler.delayedBlock).isNull()
         verify(bubbleStashController).showBubbleBarImmediate()
     }
 
@@ -370,14 +481,14 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         barAnimator.assertIsNotRunning()
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
         InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
 
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
@@ -385,6 +496,79 @@
     }
 
     @Test
+    fun animateToInitialState_expandedWhileAnimatingIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+        }
+
+        val bubbleBarAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(bubbleBarAnimator) { true }
+
+        bubbleBarAnimator.assertIsRunning()
+        assertThat(animator.isAnimating).isTrue()
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // let the animation finish
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+        assertThat(animator.isAnimating).isFalse()
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateToInitialState_expandedWhileFullyIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(animator.isAnimating).isTrue()
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+        assertThat(animator.isAnimating).isFalse()
+    }
+
+    @Test
     fun animateBubbleBarForCollapsed() {
         setUpBubbleBar()
         setUpBubbleStashController()
@@ -397,12 +581,12 @@
             BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleBarForCollapsed(bubble)
+            animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
         }
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         // verify we started animating
-        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animator.isAnimating).isTrue()
 
         // advance the animation handler by the duration of the initial lift
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -417,13 +601,149 @@
         assertThat(animatorScheduler.delayedBlock).isNotNull()
         InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
 
-        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animator.isAnimating).isFalse()
         // the bubble bar translation y should be back to its initial value
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
         verify(bubbleStashController).showBubbleBarImmediate()
     }
 
+    @Test
+    fun animateBubbleBarForCollapsed_autoExpanding() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleBarForCollapsed(bubble, isExpanding = true)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        // verify we started animating
+        assertThat(animator.isAnimating).isTrue()
+
+        // advance the animation handler by the duration of the initial lift
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animatorTestRule.advanceTimeBy(250)
+        }
+
+        // the lift animation is complete; the spring back animation should start now
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        barAnimator.assertIsRunning()
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // verify there is no hide animation
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+        assertThat(bubbleBarView.isExpanded).isTrue()
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateBubbleBarForCollapsed_expandingWhileAnimatingIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        // verify we started animating
+        assertThat(animator.isAnimating).isTrue()
+
+        // advance the animation handler by the duration of the initial lift
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animatorTestRule.advanceTimeBy(250)
+        }
+
+        // the lift animation is complete; the spring back animation should start now
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        barAnimator.assertIsRunning()
+        PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(barAnimator) { true }
+
+        // verify there is a pending hide animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        assertThat(animator.isAnimating).isTrue()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // let the animation finish
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+        assertThat(bubbleBarView.isExpanded).isTrue()
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateBubbleBarForCollapsed_expandingWhileFullyIn() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        // verify we started animating
+        assertThat(animator.isAnimating).isTrue()
+
+        // advance the animation handler by the duration of the initial lift
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animatorTestRule.advanceTimeBy(250)
+        }
+
+        // the lift animation is complete; the spring back animation should start now
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        barAnimator.assertIsRunning()
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // verify there is a pending hide animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        assertThat(animator.isAnimating).isTrue()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.expandedWhileAnimating()
+        }
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+
+        assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+        assertThat(bubbleBarView.isExpanded).isTrue()
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
     private fun setUpBubbleBar() {
         bubbleBarView = BubbleBarView(context)
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -451,14 +771,22 @@
     private fun setUpBubbleStashController() {
         bubbleStashController = mock<BubbleStashController>()
         whenever(bubbleStashController.isStashed).thenReturn(true)
-        whenever(bubbleStashController.diffBetweenHandleAndBarCenters)
+        whenever(bubbleStashController.getDiffBetweenHandleAndBarCenters())
             .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS)
-        whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation)
+        whenever(bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation())
             .thenReturn(HANDLE_TRANSLATION)
         whenever(bubbleStashController.bubbleBarTranslationYForTaskbar)
             .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
     }
 
+    private fun verifyBubbleBarIsExpandedWithTranslation(ty: Float) {
+        assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleBarView.scaleX).isEqualTo(1)
+        assertThat(bubbleBarView.scaleY).isEqualTo(1)
+        assertThat(bubbleBarView.translationY).isEqualTo(ty)
+        assertThat(bubbleBarView.isExpanded).isTrue()
+    }
+
     private fun <T> PhysicsAnimator<T>.assertIsRunning() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             assertThat(isRunning()).isTrue()
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
index 00ad3b7..0f8a2c3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
@@ -17,7 +17,7 @@
 package com.android.launcher3.taskbar.bubbles.stashing
 
 class ImmediateAction : BubbleStashController.ControllersAfterInitAction {
-    override fun runAfterInit(action: () -> Unit) = action.invoke()
+    override fun runAfterInit(action: Runnable) = action.run()
 }
 
 class DefaultDimensionsProvider(
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
index f75e542..f7e4576 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
@@ -24,6 +24,7 @@
 import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
 import com.android.launcher3.util.NavigationMode
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -31,6 +32,7 @@
 import org.junit.runner.RunWith
 
 @RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
 class TaskbarModeRuleTest {
 
     private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
index a709133..a515405 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
 import com.android.launcher3.util.window.WindowManagerProxy
 import com.google.android.apps.nexuslauncher.deviceemulator.TestWindowManagerProxy
 import com.google.common.truth.Truth.assertThat
@@ -28,6 +29,7 @@
 import org.junit.runners.model.Statement
 
 @RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
 class TaskbarPinningPreferenceRuleTest {
     private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
index 22d2079..46817d2 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
 import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.Description
@@ -26,6 +27,7 @@
 import org.junit.runners.model.Statement
 
 @RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
 class TaskbarPreferenceRuleTest {
 
     private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
index 234e499..5d4fdc5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
@@ -34,7 +34,7 @@
 import org.junit.runners.model.Statement
 
 @RunWith(LauncherMultivalentJUnit::class)
-@EmulatedDevices(["pixelFoldable2023"])
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
 class TaskbarUnitTestRuleTest {
 
     private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
index ad4b4de..4834d48 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
@@ -25,6 +25,7 @@
 import org.junit.runner.RunWith
 
 @RunWith(LauncherMultivalentJUnit::class)
+@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
 class TaskbarWindowSandboxContextTest {
 
     private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
new file mode 100644
index 0000000..1f88743
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 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.graphics.PointF
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.R
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.shared.system.InputConsumerController
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LauncherSwipeHandlerV2Test {
+
+    @Mock private lateinit var taskAnimationManager: TaskAnimationManager
+
+    private lateinit var gestureState: GestureState
+    @Mock private lateinit var inputConsumerController: InputConsumerController
+
+    @Mock private lateinit var systemUiProxy: SystemUiProxy
+
+    private lateinit var underTest: LauncherSwipeHandlerV2
+
+    @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+    private val launcherModelHelper = LauncherModelHelper()
+    private val sandboxContext = launcherModelHelper.sandboxContext
+
+    private val flingSpeed =
+        -(sandboxContext.resources.getDimension(R.dimen.quickstep_fling_threshold_speed) + 1)
+
+    @Before
+    fun setup() {
+        sandboxContext.putObject(SystemUiProxy.INSTANCE, systemUiProxy)
+        val deviceState = mock(RecentsAnimationDeviceState::class.java)
+        whenever(deviceState.rotationTouchHelper).thenReturn(mock(RotationTouchHelper::class.java))
+        gestureState = spy(GestureState(OverviewComponentObserver(sandboxContext, deviceState), 0))
+
+        underTest =
+            LauncherSwipeHandlerV2(
+                sandboxContext,
+                deviceState,
+                taskAnimationManager,
+                gestureState,
+                0,
+                false,
+                inputConsumerController
+            )
+        underTest.onGestureStarted(/* isLikelyToStartNewTask= */ false)
+    }
+
+    @Test
+    fun goHomeFromAppByTrackpad_updateEduStats() {
+        gestureState.setTrackpadGestureType(GestureState.TrackpadGestureType.THREE_FINGER)
+        underTest.onGestureEnded(flingSpeed, PointF())
+        verify(systemUiProxy)
+            .updateContextualEduStats(
+                /* isTrackpadGesture= */ eq(true),
+                eq(GestureType.HOME.toString())
+            )
+    }
+
+    @Test
+    fun goHomeFromAppByTouch_updateEduStats() {
+        underTest.onGestureEnded(flingSpeed, PointF())
+        verify(systemUiProxy)
+            .updateContextualEduStats(
+                /* isTrackpadGesture= */ eq(false),
+                eq(GestureType.HOME.toString())
+            )
+    }
+}
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 ea2e484..d2479bc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -20,8 +20,9 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.ALLOW_ROTATION
 import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
-import com.android.launcher3.LauncherPrefs.Companion.backedUpItem
+import com.android.launcher3.SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY
 import com.android.launcher3.logging.InstanceId
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_NEW_APPS_TO_HOME_SCREEN_ENABLED
@@ -32,6 +33,10 @@
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON
 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
@@ -62,6 +67,7 @@
     @Captor private lateinit var mEventCaptor: ArgumentCaptor<StatsLogManager.EventEnum>
 
     private var mDefaultThemedIcons = false
+    private var mDefaultAllowRotation = false
 
     @Before
     fun setUp() {
@@ -70,8 +76,11 @@
         whenever(mStatsLogManager.logger()).doReturn(mMockLogger)
         whenever(mStatsLogManager.logger().withInstanceId(any())).doReturn(mMockLogger)
         mDefaultThemedIcons = LauncherPrefs.get(mContext).get(THEMED_ICONS)
+        mDefaultAllowRotation = LauncherPrefs.get(mContext).get(ALLOW_ROTATION)
         // To match the default value of THEMED_ICONS
         LauncherPrefs.get(mContext).put(THEMED_ICONS, false)
+        // To match the default value of ALLOW_ROTATION
+        LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
 
         mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
     }
@@ -79,18 +88,19 @@
     @After
     fun tearDown() {
         LauncherPrefs.get(mContext).put(THEMED_ICONS, mDefaultThemedIcons)
-        mSystemUnderTest.close()
+        LauncherPrefs.get(mContext).put(ALLOW_ROTATION, mDefaultAllowRotation)
     }
 
     @Test
     fun loggingPrefs_correctDefaultValue() {
-        assertThat(mSystemUnderTest.loggingPrefs["pref_allowRotation"]!!.defaultValue).isFalse()
-        assertThat(mSystemUnderTest.loggingPrefs["pref_add_icon_to_home"]!!.defaultValue).isTrue()
-        assertThat(mSystemUnderTest.loggingPrefs["pref_overview_action_suggestions"]!!.defaultValue)
-            .isTrue()
-        assertThat(mSystemUnderTest.loggingPrefs["pref_smartspace_home_screen"]!!.defaultValue)
-            .isTrue()
-        assertThat(mSystemUnderTest.loggingPrefs["pref_enable_minus_one"]!!.defaultValue).isTrue()
+        val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+
+        assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue)
+            .isFalse()
+        assertThat(systemUnderTest.loggingPrefs[ADD_ICON_PREFERENCE_KEY]!!.defaultValue).isTrue()
+        assertThat(systemUnderTest.loggingPrefs[OVERVIEW_SUGGESTED_ACTIONS]!!.defaultValue).isTrue()
+        assertThat(systemUnderTest.loggingPrefs[SMARTSPACE_ON_HOME_SCREEN]!!.defaultValue).isTrue()
+        assertThat(systemUnderTest.loggingPrefs[KEY_ENABLE_MINUS_ONE]!!.defaultValue).isTrue()
     }
 
     @Test
@@ -101,24 +111,16 @@
         val capturedEvents = mEventCaptor.allValues
         assertThat(capturedEvents.isNotEmpty()).isTrue()
         verifyDefaultEvent(capturedEvents)
-        // pref_allowRotation false
         assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_ROTATION_DISABLED.id })
             .isTrue()
     }
 
     @Test
-    fun logSnapshot_updateValue() {
-        LauncherPrefs.get(mContext)
-            .put(
-                item =
-                    backedUpItem(
-                        sharedPrefKey = "pref_allowRotation",
-                        defaultValue = false,
-                    ),
-                value = true
-            )
+    fun logSnapshot_updateAllowRotation() {
+        LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = true)
 
-        mSystemUnderTest.logSnapshot(mInstanceId)
+        // This a new object so the values of mLoggablePrefs will be different
+        SettingsChangeLogger(mContext, mStatsLogManager).logSnapshot(mInstanceId)
 
         verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
         val capturedEvents = mEventCaptor.allValues
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 e488413..d94a351 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
@@ -65,7 +65,7 @@
         setThumbnailOverrideInternal(thumbnailOverrideMap)
     }
 
-    override fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+    override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
         setThumbnailOverrideInternal(thumbnailOverride)
     }
 
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 aee5d1e..e6534eb 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
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.graphics.Bitmap
 import android.view.Surface
+import com.android.launcher3.util.TestDispatcherProvider
 import com.android.quickstep.task.thumbnail.TaskThumbnailViewModelTest
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.GroupTask
@@ -27,10 +28,8 @@
 import com.android.systemui.shared.recents.model.ThumbnailData
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.toList
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
@@ -50,201 +49,232 @@
     private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
     private val taskIconDataSource = FakeTaskIconDataSource()
 
+    private val dispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(dispatcher)
     private val systemUnderTest =
-        TasksRepository(recentsModel, taskThumbnailDataSource, taskIconDataSource)
+        TasksRepository(
+            recentsModel,
+            taskThumbnailDataSource,
+            taskIconDataSource,
+            testScope.backgroundScope,
+            TestDispatcherProvider(dispatcher)
+        )
 
     @Test
-    fun getAllTaskDataReturnsFlattenedListOfTasks() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
+    fun getAllTaskDataReturnsFlattenedListOfTasks() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
 
-        assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
-    }
-
-    @Test
-    fun getTaskDataByIdReturnsSpecificTask() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
-    }
-
-    @Test
-    fun setVisibleTasksPopulatesThumbnails() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        assertThat(systemUnderTest.getTaskDataById(1).drop(1).first()!!.thumbnail!!.thumbnail)
-            .isEqualTo(bitmap1)
-        assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
-            .isEqualTo(bitmap2)
-    }
-
-    @Test
-    fun setVisibleTasksPopulatesIcons() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        systemUnderTest
-            .getTaskDataById(1)
-            .drop(1)
-            .first()!!
-            .assertHasIconDataFromSource(taskIconDataSource)
-        systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
-    }
-
-    @Test
-    fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        assertThat(systemUnderTest.getTaskDataById(2).drop(1).first()!!.thumbnail!!.thumbnail)
-            .isEqualTo(bitmap2)
-
-        // Prevent new loading of Bitmaps
-        taskThumbnailDataSource.shouldLoadSynchronously = false
-        systemUnderTest.setVisibleTasks(listOf(2, 3))
-
-        assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
-            .isEqualTo(bitmap2)
-    }
-
-    @Test
-    fun changingVisibleTasksContainsAlreadyPopulatedIcons() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from icon was loaded.
-        systemUnderTest
-            .getTaskDataById(2)
-            .drop(1)
-            .first()!!
-            .assertHasIconDataFromSource(taskIconDataSource)
-
-        // Prevent new loading of Drawables
-        taskThumbnailDataSource.shouldLoadSynchronously = false
-        systemUnderTest.setVisibleTasks(listOf(2, 3))
-
-        systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
-    }
-
-    @Test
-    fun retrievedImagesAreDiscardedWhenTaskBecomesInvisible() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        val task2 = systemUnderTest.getTaskDataById(2).drop(1).first()!!
-        assertThat(task2.thumbnail!!.thumbnail).isEqualTo(bitmap2)
-        task2.assertHasIconDataFromSource(taskIconDataSource)
-
-        // Prevent new loading of Bitmaps
-        taskThumbnailDataSource.shouldLoadSynchronously = false
-        taskIconDataSource.shouldLoadSynchronously = false
-        systemUnderTest.setVisibleTasks(listOf(0, 1))
-
-        val task2AfterVisibleTasksChanged = systemUnderTest.getTaskDataById(2).first()!!
-        assertThat(task2AfterVisibleTasksChanged.thumbnail).isNull()
-        assertThat(task2AfterVisibleTasksChanged.icon).isNull()
-        assertThat(task2AfterVisibleTasksChanged.titleDescription).isNull()
-        assertThat(task2AfterVisibleTasksChanged.title).isNull()
-    }
-
-    @Test
-    fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() = runTest {
-        // Setup fakes
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        taskThumbnailDataSource.shouldLoadSynchronously = false
-
-        // Setup TasksRepository
-        systemUnderTest.getAllTaskData(forceRefresh = true)
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // Assert there is no bitmap in first emission
-        val taskFlow = systemUnderTest.getTaskDataById(2)
-        val taskFlowValuesList = mutableListOf<Task?>()
-        backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
-            taskFlow.toList(taskFlowValuesList)
+            assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
         }
-        assertThat(taskFlowValuesList[0]!!.thumbnail).isNull()
-
-        // Simulate bitmap loading after first emission
-        taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
-
-        // Check for second emission
-        assertThat(taskFlowValuesList[1]!!.thumbnail!!.thumbnail).isEqualTo(bitmap2)
-    }
 
     @Test
-    fun setThumbnailOverrideOverrideThumbnails() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        val thumbnailOverride = createThumbnailData()
-        systemUnderTest.getAllTaskData(forceRefresh = true)
+    fun getTaskDataByIdReturnsSpecificTask() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
 
-        systemUnderTest.setVisibleTasks(listOf(1))
-        systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
-            .isEqualTo(bitmap1)
-        assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
-    }
+            assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
+        }
 
     @Test
-    fun setThumbnailOverrideClearedWhenTaskBecomeInvisible() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-        val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
-        val thumbnailOverride = createThumbnailData()
-        systemUnderTest.getAllTaskData(forceRefresh = true)
+    fun setVisibleTasksPopulatesThumbnails() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+            systemUnderTest.getAllTaskData(forceRefresh = true)
 
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-        systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
-        systemUnderTest.setVisibleTasks(listOf(1))
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
 
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
-            .isEqualTo(bitmap1)
-        assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
-    }
+            assertThat(systemUnderTest.getTaskDataById(1).first()!!.thumbnail!!.thumbnail)
+                .isEqualTo(bitmap1)
+            assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+                .isEqualTo(bitmap2)
+        }
 
     @Test
-    fun setThumbnailOverrideDoesNotOverrideInvisibleTasks() = runTest {
-        recentsModel.seedTasks(defaultTaskList)
-        val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
-        val thumbnailOverride = createThumbnailData()
-        systemUnderTest.getAllTaskData(forceRefresh = true)
+    fun setVisibleTasksPopulatesIcons() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
 
-        systemUnderTest.setVisibleTasks(listOf(1, 2))
-        systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
 
-        // .drop(1) to ignore initial null content before from thumbnail was loaded.
-        assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
-            .isEqualTo(bitmap1)
-        assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
-            .isEqualTo(thumbnailOverride.thumbnail)
-    }
+            systemUnderTest
+                .getTaskDataById(1)
+                .first()!!
+                .assertHasIconDataFromSource(taskIconDataSource)
+            systemUnderTest
+                .getTaskDataById(2)
+                .first()!!
+                .assertHasIconDataFromSource(taskIconDataSource)
+        }
+
+    @Test
+    fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+            assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+                .isEqualTo(bitmap2)
+
+            // Prevent new loading of Bitmaps
+            taskThumbnailDataSource.shouldLoadSynchronously = false
+            systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+            assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+                .isEqualTo(bitmap2)
+        }
+
+    @Test
+    fun changingVisibleTasksContainsAlreadyPopulatedIcons() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+            systemUnderTest
+                .getTaskDataById(2)
+                .first()!!
+                .assertHasIconDataFromSource(taskIconDataSource)
+
+            // Prevent new loading of Drawables
+            taskThumbnailDataSource.shouldLoadSynchronously = false
+            systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+            systemUnderTest
+                .getTaskDataById(2)
+                .first()!!
+                .assertHasIconDataFromSource(taskIconDataSource)
+        }
+
+    @Test
+    fun retrievedImagesAreDiscardedWhenTaskBecomesInvisible() =
+        testScope.runTest {
+            recentsModel.seedTasks(defaultTaskList)
+            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+            val task2 = systemUnderTest.getTaskDataById(2).first()!!
+            assertThat(task2.thumbnail!!.thumbnail).isEqualTo(bitmap2)
+            task2.assertHasIconDataFromSource(taskIconDataSource)
+
+            // Prevent new loading of Bitmaps
+            taskThumbnailDataSource.shouldLoadSynchronously = false
+            taskIconDataSource.shouldLoadSynchronously = false
+            systemUnderTest.setVisibleTasks(listOf(0, 1))
+
+            val task2AfterVisibleTasksChanged = systemUnderTest.getTaskDataById(2).first()!!
+            assertThat(task2AfterVisibleTasksChanged.thumbnail).isNull()
+            assertThat(task2AfterVisibleTasksChanged.icon).isNull()
+            assertThat(task2AfterVisibleTasksChanged.titleDescription).isNull()
+            assertThat(task2AfterVisibleTasksChanged.title).isNull()
+        }
+
+    @Test
+    fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() =
+        testScope.runTest {
+            // Setup fakes
+            recentsModel.seedTasks(defaultTaskList)
+            val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+            taskThumbnailDataSource.shouldLoadSynchronously = false
+
+            // Setup TasksRepository
+            systemUnderTest.getAllTaskData(forceRefresh = true)
+            systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+            // Assert there is no bitmap in first emission
+            assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail).isNull()
+
+            // Simulate bitmap loading after first emission
+            taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
+
+            // Check for second emission
+            assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+                .isEqualTo(bitmap2)
+        }
+
+    @Test
+    fun addThumbnailOverrideOverrideThumbnails() =
+        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)
+        }
 
     private fun createTaskWithId(taskId: Int) =
         Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
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 00dbcc1..dc16475 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
@@ -72,9 +72,8 @@
 
     @Test
     fun thumbnailOverrideWaitAndReset() = runTest {
-        val thumbnailData1 = createThumbnailData()
-        val thumbnailData2 = createThumbnailData()
-        val thumbnailDataOverride = createThumbnailData()
+        val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
+        val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
         tasksRepository.seedTasks(tasks)
         tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
 
@@ -87,15 +86,16 @@
         assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
         assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
 
-        val thumbnailUpdate = mapOf(2 to thumbnailDataOverride)
         systemUnderTest.setRunningTaskShowScreenshot(true)
-        systemUnderTest.setThumbnailOverride(thumbnailUpdate)
+        val thumbnailOverride = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
+        systemUnderTest.addOrUpdateThumbnailOverride(thumbnailOverride)
 
         systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
-        systemUnderTest.waitForThumbnailsToUpdate(thumbnailUpdate)
+        val expectedUpdate = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
+        systemUnderTest.waitForThumbnailsToUpdate(expectedUpdate)
 
         assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
-        assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailDataOverride)
+        assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
 
         systemUnderTest.onReset()
 
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
index ef3a833..67a0ee4 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
@@ -202,7 +202,7 @@
         boolean hoverHandled =
                 mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
 
-        assertThat(hoverHandled).isFalse();
+        assertThat(hoverHandled).isTrue();
     }
 
     @Test
@@ -213,7 +213,7 @@
         boolean hoverHandled =
                 mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
 
-        assertThat(hoverHandled).isFalse();
+        assertThat(hoverHandled).isTrue();
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index 1886ce6..a8f39af 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -31,6 +31,10 @@
 
     static final int STRESS_REPEAT_COUNT = 10;
 
+    private enum TestCase {
+        TO_HOME, TO_OVERVIEW,
+    }
+
     @Override
     @Before
     public void setUp() throws Exception {
@@ -41,28 +45,55 @@
     }
 
     @Test
-    @NavigationModeSwitch
+    @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
     public void testStressPressHome() {
-        for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
-            // Destroy Launcher activity.
-            closeLauncherActivity();
-
-            // The test action.
-            mLauncher.goHome();
-        }
+        runTest(TestCase.TO_HOME);
     }
 
     @Test
-    @NavigationModeSwitch
+    @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.ZERO_BUTTON)
+    public void testStressSwipeHome() {
+        runTest(TestCase.TO_HOME);
+    }
+
+    @Test
+    @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
+    public void testStressPressOverview() {
+        runTest(TestCase.TO_OVERVIEW);
+    }
+
+    @Test
+    @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.ZERO_BUTTON)
     public void testStressSwipeToOverview() {
+        runTest(TestCase.TO_OVERVIEW);
+    }
+
+    private void runTest(TestCase testCase) {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
             closeLauncherActivity();
 
             // The test action.
-            mLauncher.getLaunchedAppState().switchToOverview();
+            switch (testCase) {
+                case TO_OVERVIEW:
+                    mLauncher.getLaunchedAppState().switchToOverview();
+                    break;
+                case TO_HOME:
+                    mLauncher.goHome();
+                    break;
+                default:
+                    throw new IllegalStateException("Cannot run test case: " + testCase);
+            }
         }
-        closeLauncherActivity();
-        mLauncher.goHome();
+        switch (testCase) {
+            case TO_OVERVIEW:
+                closeLauncherActivity();
+                mLauncher.goHome();
+                break;
+            case TO_HOME:
+            default:
+                // No-Op
+                break;
+        }
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
new file mode 100644
index 0000000..694a382
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.IgnoreLimit
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.launcher3.BuildConfig
+import com.android.launcher3.ui.AbstractLauncherUiTest
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+
+/** Test Desktop windowing in Overview. */
+@AllowedDevices(allowed = [DeviceProduct.CF_TABLET, DeviceProduct.TANGORPRO])
+@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
+class TaplTestsOverviewDesktop : AbstractLauncherUiTest<QuickstepLauncher?>() {
+    @Before
+    fun setup() {
+        val overview = mLauncher.goHome().switchToOverview()
+        if (overview.hasTasks()) {
+            overview.dismissAllTasks()
+        }
+        startTestAppsWithCheck()
+        mLauncher.goHome()
+    }
+
+    @Test
+    @PortraitLandscape
+    fun enterDesktopViaOverviewMenu() {
+        // Move last launched TEST_ACTIVITY_2 into Desktop
+        mLauncher.workspace
+            .switchToOverview()
+            .getTestActivityTask(TEST_ACTIVITY_2)
+            .tapMenu()
+            .tapDesktopMenuItem()
+        assertTestAppLaunched(TEST_ACTIVITY_2)
+
+        // Scroll back to TEST_ACTIVITY_1, then move it into Desktop
+        mLauncher
+            .goHome()
+            .switchToOverview()
+            .apply { flingForward() }
+            .getTestActivityTask(TEST_ACTIVITY_1)
+            .tapMenu()
+            .tapDesktopMenuItem()
+        TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+
+        // Launch static DesktopTaskView
+        val desktop =
+            mLauncher.goHome().switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+        TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+
+        // Launch live-tile DesktopTaskView
+        desktop.switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+        TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+    }
+
+    private fun startTestAppsWithCheck() {
+        TEST_ACTIVITIES.forEach {
+            startTestActivity(it)
+            executeOnLauncher { launcher ->
+                assertWithMessage(
+                        "Launcher activity is the top activity; expecting TestActivity$it"
+                    )
+                    .that(isInLaunchedApp(launcher))
+                    .isTrue()
+            }
+        }
+    }
+
+    private fun assertTestAppLaunched(index: Int) {
+        assertWithMessage("TestActivity$index not opened in Desktop")
+            .that(
+                mDevice.wait(
+                    Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity$index")),
+                    DEFAULT_UI_TIMEOUT
+                )
+            )
+            .isTrue()
+    }
+
+    companion object {
+        const val TEST_ACTIVITY_1 = 2
+        const val TEST_ACTIVITY_2 = 3
+        val TEST_ACTIVITIES = listOf(TEST_ACTIVITY_1, TEST_ACTIVITY_2)
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 1dfab26..cb815fe 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -356,6 +356,7 @@
 
     @Test
     @TaskbarModeSwitch
+    @ScreenRecord // b/358607191
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 2d79623..3a83ae3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.quickstep;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
@@ -71,7 +71,7 @@
         final ArgumentCaptor<ActivityOptions> optionsCaptor =
                 ArgumentCaptor.forClass(ActivityOptions.class);
         verify(mSystemUiProxy).startRecentsActivity(any(), optionsCaptor.capture(), any());
-        assertTrue(optionsCaptor.getValue()
-                .isPendingIntentBackgroundActivityLaunchAllowedByPermission());
+        assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS,
+                optionsCaptor.getValue().getPendingIntentBackgroundActivityStartMode());
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index 512557b..dc1da69 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -88,18 +88,6 @@
     }
 
     @Test
-    public void showBorderOnHoverEvent() {
-        mTaskView.setBorderEnabled(/* enabled= */ true);
-        MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
-        mTaskView.onHoverEvent(MotionEvent.obtain(event));
-        verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
-                true);
-        mTaskView.onFocusChanged(true, 0, new Rect());
-        verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
-                true);
-    }
-
-    @Test
     public void showBorderOnBorderEnabled() {
         presetBorderStatus(/* enabled= */ false);
         mTaskView.setBorderEnabled(/* enabled= */ true);
diff --git a/res/color-night-v31/material_color_surface_container_lowest.xml b/res/color-night-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..4396f6d
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="4" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_lowest.xml b/res/color-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..f726aea
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="100" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_bubble_button.xml b/res/drawable/ic_bubble_button.xml
new file mode 100644
index 0000000..1ed212e
--- /dev/null
+++ b/res/drawable/ic_bubble_button.xml
@@ -0,0 +1,25 @@
+<?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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="20dp"
+        android:height="20dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/res/drawable/ic_desktop_with_bg.xml b/res/drawable/ic_desktop_with_bg.xml
new file mode 100644
index 0000000..f54285c
--- /dev/null
+++ b/res/drawable/ic_desktop_with_bg.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M24,2L24,2A22,22 0,0 1,46 24L46,24A22,22 0,0 1,24 46L24,46A22,22 0,0 1,2 24L2,24A22,22 0,0 1,24 2z"
+      android:fillColor="#ffffff"/>
+  <path
+      android:pathData="M32,30H16V18H32V30ZM32,32C33.1,32 34,31.1 34,30V18C34,16.9 33.1,16 32,16H16C14.9,16 14,16.9 14,18V30C14,31.1 14.9,32 16,32H32ZM30,20H23V22H28V24H30V20ZM18,23H27V28H18V23Z"
+      android:fillColor="#000000"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/res/drawable/private_space_install_app_icon.xml b/res/drawable/private_space_install_app_icon.xml
index 12c4a82..cfec2b1 100644
--- a/res/drawable/private_space_install_app_icon.xml
+++ b/res/drawable/private_space_install_app_icon.xml
@@ -23,9 +23,9 @@
             android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z" />
         <path
             android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z"
-            android:fillColor="?attr/materialColorSurfaceContainerLowest" />
+            android:fillColor="@color/material_color_surface_container_lowest" />
         <path
             android:pathData="M29 31h-6v-2h6v-6h2v6h6v2h-6v6h-2v-6Z"
-            android:fillColor="?attr/materialColorOnSurface" />
+            android:fillColor="@color/material_color_on_surface" />
     </group>
 </vector>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index e68f0f3..6bce220 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -100,6 +100,7 @@
         android:gravity="center_vertical"
         android:layout_marginStart="@dimen/ps_header_layout_margin"
         android:text="@string/ps_container_title"
+        android:maxLines="1"
         android:theme="@style/PrivateSpaceHeaderTextStyle"
         android:importantForAccessibility="no"/>
 
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index dca7cab..8b4b26a 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -92,6 +92,8 @@
     <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="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 3e0eaf7..03f62bf 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -92,6 +92,8 @@
     <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="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 794c249..31ebd34 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -92,6 +92,8 @@
     <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="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 55a80b4..e2f4ecd 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -92,6 +92,8 @@
     <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="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 7713e89..520295e 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -92,6 +92,8 @@
     <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="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 71bd34c..09ddf76 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -92,6 +92,8 @@
     <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="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 edb9a35..85792f7 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -92,6 +92,8 @@
     <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="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 3d39828..baf405d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -92,6 +92,8 @@
     <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="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 09ebf2f..a6bdde1 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -92,6 +92,8 @@
     <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="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 346a7ea..0de15da 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -92,6 +92,8 @@
     <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="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 9da16bb..18753ba 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -92,6 +92,8 @@
     <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="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 63858d3..e2e5ebf 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -92,6 +92,8 @@
     <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="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 99b1bf2..31b6437 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -92,6 +92,8 @@
     <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="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 d052fba..2abbf4c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -92,6 +92,8 @@
     <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="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 5a178a4..d4322b1 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c9579a5..33a3c4d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -92,6 +92,8 @@
     <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="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-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 311b4b9..de41d2c 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -92,6 +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>
+    <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 c9579a5..33a3c4d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c9579a5..33a3c4d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -92,6 +92,8 @@
     <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="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-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 047a67f..a856340 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -92,6 +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>
+    <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 f5b4d8a..793e5f2 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -92,6 +92,8 @@
     <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="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 92e4a2d0..01b053c 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c2be8cd..231d0f7 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -92,6 +92,8 @@
     <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="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 4a9ae90..1c734b1 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -92,6 +92,8 @@
     <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="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 0047f8d..a8a5491 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -48,7 +48,7 @@
     <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="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"بایدها"</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>
@@ -92,6 +92,8 @@
     <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="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-fi/strings.xml b/res/values-fi/strings.xml
index 9eaaeb6..0cf15f4 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -92,6 +92,8 @@
     <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="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 5490ee3..447909a 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -92,6 +92,8 @@
     <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="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 6e04abd..48c3bde 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -92,6 +92,8 @@
     <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="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 e68d0e5..61a7e3d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -92,6 +92,8 @@
     <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="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 92d52a7..b85038c 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -92,6 +92,8 @@
     <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="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 79fcc3f..1205515 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -92,6 +92,8 @@
     <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="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 eaf1b55..1238172 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c33cb5a..acd4156 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -92,6 +92,8 @@
     <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="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 f06ff83..2c020ad 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -92,6 +92,8 @@
     <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="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 8487e62..6586bb4 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -92,6 +92,8 @@
     <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="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 ab343e5..f4593ec 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -92,6 +92,8 @@
     <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="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 378d1e9..a444d21 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -92,6 +92,8 @@
     <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="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 2e8cacb..3a45b9f 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -92,6 +92,8 @@
     <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="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 e0aa65f..9dacea1 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -92,6 +92,8 @@
     <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="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 1d674cb..9e0e4a9 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -92,6 +92,8 @@
     <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="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 363fc2f..48f3478 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -92,6 +92,8 @@
     <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="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 ab5decf..0044e6a 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -92,6 +92,8 @@
     <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="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 04daaac..f2d4e55 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -92,6 +92,8 @@
     <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="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 7aa9e03..f3e5a3a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -92,6 +92,8 @@
     <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="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 d0079d0..e955666 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -92,6 +92,8 @@
     <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="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 9572f3d..78fe222 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -92,6 +92,8 @@
     <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="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 6cd8872..4954848 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -92,6 +92,8 @@
     <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="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 426fdc0..49e9825 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c84f232..626a80e 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -92,6 +92,8 @@
     <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="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 ff06bcf..b777e0f 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/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,6 +92,8 @@
     <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="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 d9b220c..6fe7967 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -92,6 +92,8 @@
     <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="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 2f78245..22d789b 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -92,6 +92,8 @@
     <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="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 d2fd7a8..9320e45 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -92,6 +92,8 @@
     <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="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 946d8df..599c9a1 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -92,6 +92,8 @@
     <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="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 5c0158c..11b076c 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -92,6 +92,8 @@
     <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="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 eddcefb..add65ee 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -92,6 +92,8 @@
     <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="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-night-v31/colors.xml b/res/values-night-v31/colors.xml
index 07c450e..0f630e5 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -57,4 +57,6 @@
         @android:color/system_accent1_200</color>
     <color name="work_fab_icon_color">
         @android:color/system_accent1_900</color>
+
+    <color name="material_color_on_surface">@android:color/system_neutral1_100</color>
 </resources>
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
new file mode 100644
index 0000000..887a2a5
--- /dev/null
+++ b/res/values-night/colors.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <color name="material_color_surface_container_lowest">#0D0E11</color>
+    <color name="material_color_on_surface">#E3E2E6</color>
+</resources>
\ No newline at end of file
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3402086..c2bc5e0 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -92,6 +92,8 @@
     <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="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 74001c7..01c6dfc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -92,6 +92,8 @@
     <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="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 e72d1f3..dce05ae 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -92,6 +92,8 @@
     <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="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 76ddbdc..fae07369 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -92,6 +92,8 @@
     <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="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 1f98805..69b63cf 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -92,6 +92,8 @@
     <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="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 20edc93..f4ee373 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -92,6 +92,8 @@
     <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="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 ec8e558..5293657 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -92,6 +92,8 @@
     <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="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 c941cba..0e8faa1 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -92,6 +92,8 @@
     <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="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 298a078..9db82a7 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -92,6 +92,8 @@
     <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="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 94d109c..5007a7f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -92,6 +92,8 @@
     <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="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 6ee5e07..ab2eff3 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -92,6 +92,8 @@
     <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="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 f106fab..a61cd6d 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -92,6 +92,8 @@
     <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="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 a9c4e24..621046f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -92,6 +92,8 @@
     <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="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 5806d1e..812cbd7 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -92,6 +92,8 @@
     <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="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 5d69573..5464af3 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -92,6 +92,8 @@
     <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="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 559843a..29ca948 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -92,6 +92,8 @@
     <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="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 cf18156..038f6b7 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -92,6 +92,8 @@
     <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="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 706c4f4..72684cd 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -92,6 +92,8 @@
     <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="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 d99ffdc..ec265c7 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -92,6 +92,8 @@
     <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="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 09939b3..dd4dab6 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -92,6 +92,8 @@
     <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="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 0c9ee22..7048517 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -92,6 +92,8 @@
     <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="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 8312ece..8460f73 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -92,6 +92,8 @@
     <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="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 8f41d49..be02e01 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -92,6 +92,8 @@
     <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="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-v31/colors.xml b/res/values-v31/colors.xml
index 5c81d49..a5cdfc7 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -110,4 +110,6 @@
         @android:color/system_accent1_900</color>
 
     <color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
+
+    <color name="material_color_on_surface">@android:color/system_neutral1_900</color>
 </resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index af4a773..3d8b815 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -92,6 +92,8 @@
     <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="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>
@@ -129,7 +131,7 @@
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Thay đổi cài đặt"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Hiện dấu chấm thông báo"</string>
-    <string name="developer_options_title" msgid="700788437593726194">"Tùy chọn cho nhà phát triển"</string>
+    <string name="developer_options_title" msgid="700788437593726194">"Tuỳ chọn cho nhà phát triển"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Thêm biểu tượng ứng dụng vào màn hình chính"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Cho ứng dụng mới"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3435eb0..12a3a70 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,6 +92,8 @@
     <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="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 950d54b..c82a320 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -92,6 +92,8 @@
     <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="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 331071d..714fc24 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -92,6 +92,8 @@
     <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="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 d167f14..a84b1fb 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -92,6 +92,8 @@
     <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="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/colors.xml b/res/values/colors.xml
index c82358b..3f8bede 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -142,6 +142,9 @@
     <color name="widget_cell_title_color_dark">@color/system_on_surface_dark</color>
     <color name="widget_cell_subtitle_color_dark">@color/system_on_surface_variant_dark</color>
 
+    <color name="material_color_surface_container_lowest">#FFFFFF</color>
+    <color name="material_color_on_surface">#1B1B1F</color>
+
     <color name="system_primary_container_light">#D9E2FF</color>
     <color name="system_on_primary_container_light">#001945</color>
     <color name="system_primary_light">#475D92</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2a3b588..507ce9a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -77,6 +77,7 @@
     <string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
     <string name="launcher_restore_event_logger_class" translatable="false"></string>
     <string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
+    <string name="contextual_edu_manager_class" translatable="false"></string>
     <!--  Used for determining category of a widget presented in widget recommendations. -->
     <string name="widget_recommendation_category_provider_class" translatable="false"></string>
     <string name="api_wrapper_class" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index af91b5a..5e1d8a5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -306,6 +306,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>
 
     <!-- Pending widget -->
     <dimen name="pending_widget_min_padding">8dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3b458c2..fd724a5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -215,7 +215,8 @@
     <string name="dismiss_prediction_label">Don\'t suggest app</string>
     <!-- Label for pinning predicted app. -->
     <string name="pin_prediction">Pin Prediction</string>
-
+    <!-- Label for bubbling a launcher item. [CHAR_LIMIT=20] -->
+    <string name="bubble">Bubble</string>
 
     <!-- Permissions: -->
     <skip />
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 876b643..d3ee364 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -138,9 +138,6 @@
     public static final int TYPE_TOUCH_CONTROLLER_NO_INTERCEPT = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE
             & ~TYPE_LISTENER & ~TYPE_TASKBAR_OVERLAYS;
 
-    public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP
-            & ~TYPE_PIN_IME_POPUP;
-
     protected boolean mIsOpen;
 
     public AbstractFloatingView(Context context, AttributeSet attrs) {
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 8585b66..177b28c 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -140,15 +140,11 @@
     }
 
     protected void onDeviceProfileInitiated() {
-        if (mDeviceProfile.isVerticalBarLayout()) {
-            mDeviceProfile.updateIsSeascape(this);
-        }
     }
 
     @Override
     public void onDisplayInfoChanged(Context context, Info info, int flags) {
         if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.isVerticalBarLayout()) {
-            mDeviceProfile.updateIsSeascape(this);
             reapplyUi();
         }
     }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5134dbe..1eccbff 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -504,7 +504,7 @@
             mLastOriginalText = label;
             mLastModifiedText = mLastOriginalText;
             mBreakPointsIntArray = StringMatcherUtility.getListOfBreakpoints(label, MATCHER);
-            if (Flags.enableNewArchivingIcon()
+            if (Flags.useNewIconForArchivedApps()
                     && info instanceof ItemInfoWithIcon infoWithIcon
                     && infoWithIcon.isInactiveArchive()) {
                 setTextWithArchivingIcon(label);
@@ -820,7 +820,7 @@
                     getLineSpacingExtra());
             if (!TextUtils.equals(modifiedString, mLastModifiedText)) {
                 mLastModifiedText = modifiedString;
-                if (Flags.enableNewArchivingIcon()
+                if (Flags.useNewIconForArchivedApps()
                         && getTag() instanceof ItemInfoWithIcon infoWithIcon
                         && infoWithIcon.isInactiveArchive()) {
                     setTextWithArchivingIcon(modifiedString);
@@ -873,7 +873,7 @@
         if (drawable == null) {
             setText(text);
             Log.w(TAG, "setTextWithStartIcon: start icon Drawable not found from resources"
-                    + ", will just set text instead. text=" + text);
+                    + ", will just set text instead.");
             return;
         }
         drawable.setTint(getCurrentTextColor());
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1a5f4b9..5cbf6fb 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -65,7 +65,6 @@
 import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
 import com.android.launcher3.responsive.ResponsiveSpecsProvider;
 import com.android.launcher3.util.CellContentDimensions;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.IconSizeSteps;
 import com.android.launcher3.util.ResourceHelper;
@@ -298,9 +297,6 @@
     // the widgetView, such that the actual view size is same as the widget size.
     public final Rect widgetPadding = new Rect();
 
-    // When true, nav bar is on the left side of the screen.
-    private boolean mIsSeascape;
-
     // Notification dots
     public final DotRenderer mDotRendererWorkSpace;
     public final DotRenderer mDotRendererAllApps;
@@ -2007,25 +2003,8 @@
         return isLandscape && transposeLayoutWithOrientation;
     }
 
-    /**
-     * Updates orientation information and returns true if it has changed from the previous value.
-     */
-    public boolean updateIsSeascape(Context context) {
-        if (isVerticalBarLayout()) {
-            boolean isSeascape = DisplayController.INSTANCE.get(context)
-                    .getInfo().rotation == Surface.ROTATION_270;
-            if (mIsSeascape != isSeascape) {
-                mIsSeascape = isSeascape;
-                // Hotseat changing sides requires updating workspace left/right paddings
-                updateWorkspacePadding();
-                return true;
-            }
-        }
-        return false;
-    }
-
     public boolean isSeascape() {
-        return isVerticalBarLayout() && mIsSeascape;
+        return rotationHint == Surface.ROTATION_270 && isVerticalBarLayout();
     }
 
     public boolean shouldFadeAdjacentWorkspaceScreens() {
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 960d77a..de1748b 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -20,7 +20,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -29,7 +28,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 
 
@@ -189,10 +187,6 @@
      * Scrolls this recycler view to the top.
      */
     public void scrollToTop() {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.PRIVATE_SPACE_SCROLL_FAILURE, "FastScrollRecyclerView#scrollToTop",
-                    new Exception());
-        }
         if (mScrollbar != null) {
             mScrollbar.reattachThumbToScroll();
         }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6c706be..fac372b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2708,6 +2708,10 @@
         mWidgetPickerDataProvider.dump(prefix, writer);
         mDeviceProfile.dump(this, prefix, writer);
         mAppsView.getAppsStore().dump(prefix, writer);
+        mAppsView.getPersonalAppList().dump(prefix, writer);
+        if (mAppsView.shouldShowTabs()) {
+            mAppsView.getWorkAppList().dump(prefix, writer);
+        }
 
         try {
             FileLog.flushAll(writer);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 08ccfb2..15641ab 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -115,7 +115,7 @@
         if (BuildCompat.isAtLeastV() && Flags.enableSupportForArchiving()) {
             ArchiveCompatibilityParams params = new ArchiveCompatibilityParams();
             params.setEnableUnarchivalConfirmation(false);
-            params.setEnableIconOverlay(!Flags.enableNewArchivingIcon());
+            params.setEnableIconOverlay(!Flags.useNewIconForArchivedApps());
             launcherApps.setArchiveCompatibility(params);
         }
 
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index ad660d2..227ac2b 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.Flags.enableExpandingPauseWorkButton;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.WORK;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
@@ -1313,6 +1314,10 @@
         return mAH.get(MAIN).mAppsList;
     }
 
+    public AlphabeticalAppsList<T> getWorkAppList() {
+        return mAH.get(WORK).mAppsList;
+    }
+
     public FloatingHeaderView getFloatingHeaderView() {
         return mHeader;
     }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 9271596..6dd811a 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -26,6 +26,7 @@
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.ImageSpan;
+import android.util.Log;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -39,6 +40,7 @@
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.views.ActivityContext;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -270,6 +272,7 @@
         List<AdapterItem> oldItems = new ArrayList<>(mAdapterItems);
         // Prepare to update the list of sections, filtered apps, etc.
         mFastScrollerSections.clear();
+        Log.d(TAG, "Clearing FastScrollerSections.");
         mAdapterItems.clear();
         mAccessibilityResultsCount = 0;
 
@@ -290,6 +293,7 @@
                     mFastScrollerSections.add(new FastScrollSectionInfo(
                             mActivityContext.getResources().getString(
                                     R.string.work_profile_edu_section), 0));
+                    Log.d(TAG, "Adding FastScrollSection for work edu card.");
                 }
                 position = addAppsWithSections(mApps, position);
             }
@@ -303,6 +307,7 @@
                 mFastScrollerSections.add(new FastScrollSectionInfo(
                         mFastScrollerSections.get(mFastScrollerSections.size() - 1).sectionName,
                         position++));
+                Log.d(TAG, "Adding FastScrollSection duplicate to scroll to the bottom.");
             }
         }
         mAccessibilityResultsCount = (int) mAdapterItems.stream()
@@ -346,6 +351,7 @@
                 && !mPrivateApps.isEmpty()) {
             // Always add PS Header if Space is present and visible.
             position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+            Log.d(TAG, "Adding FastScrollSection for Private Space header. ");
             mFastScrollerSections.add(new FastScrollSectionInfo(
                     mPrivateProfileAppScrollerBadge, position));
             int privateSpaceState = mPrivateProviderManager.getCurrentState();
@@ -407,14 +413,14 @@
             hasPrivateApps = appList.stream().
                     allMatch(mPrivateProviderManager.getItemInfoMatcher());
         }
+        Log.d(TAG, "Adding apps with sections. HasPrivateApps: " + hasPrivateApps);
         for (int i = 0; i < appList.size(); i++) {
             AppInfo info = appList.get(i);
             // Apply decorator to private apps.
             if (hasPrivateApps) {
                 mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info,
-                        new SectionDecorationInfo(mActivityContext.getApplicationContext(),
-                                getRoundRegions(i, appList.size()),
-                                true /* decorateTogether */)));
+                        new SectionDecorationInfo(mActivityContext,
+                                getRoundRegions(i, appList.size()), true /* decorateTogether */)));
             } else {
                 mAdapterItems.add(AdapterItem.asApp(info));
             }
@@ -422,6 +428,8 @@
             String sectionName = info.sectionName;
             // Create a new section if the section names do not match
             if (!sectionName.equals(lastSectionName)) {
+                Log.d(TAG, "addAppsWithSections: adding sectionName: " + sectionName
+                    + " with appInfoTitle: " + info.title);
                 lastSectionName = sectionName;
                 mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
                         mPrivateProfileAppScrollerBadge : sectionName, position));
@@ -472,6 +480,13 @@
         return mPrivateProviderManager;
     }
 
+    public void dump(String prefix, PrintWriter writer) {
+        writer.println(prefix + "SectionInfo[] size: " + mFastScrollerSections.size());
+        for (int i = 0; i < mFastScrollerSections.size(); i++) {
+            writer.println("\tFastScrollSection: " + mFastScrollerSections.get(i).sectionName);
+        }
+    }
+
     private static class MyDiffCallback extends DiffUtil.Callback {
 
         private final List<AdapterItem> mOldList;
diff --git a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
index 4f8d53e..d593f80 100644
--- a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
+++ b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
@@ -3,6 +3,7 @@
 import android.content.Context;
 import android.icu.text.AlphabeticIndex;
 import android.os.LocaleList;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 
@@ -12,6 +13,9 @@
 
 public class AlphabeticIndexCompat {
 
+    // TODO(b/336947811): Set to false after root causing is done.
+    private static final boolean DEBUG = true;
+    private static final String TAG = "AlphabeticIndexCompat";
     private static final String MID_DOT = "\u2219";
     private final String mDefaultMiscLabel;
 
@@ -49,6 +53,9 @@
     public String computeSectionName(@NonNull CharSequence cs) {
         String s = Utilities.trim(cs);
         String sectionName = mBaseIndex.getBucket(mBaseIndex.getBucketIndex(s)).getLabel();
+        if (DEBUG) {
+            Log.d(TAG, "computeSectionName: cs: " + cs + " sectionName: " + sectionName);
+        }
         if (Utilities.trim(sectionName).isEmpty() && s.length() > 0) {
             int c = s.codePointAt(0);
             boolean startsWithDigit = Character.isDigit(c);
diff --git a/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java b/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java
new file mode 100644
index 0000000..da13546
--- /dev/null
+++ b/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 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.contextualeducation;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.systemui.contextualeducation.GestureType;
+
+/**
+ * A class to update contextual education data. It is a no-op implementation and could be
+ * overridden by changing the resource value [R.string.contextual_edu_manager_class] to provide
+ * a real implementation.
+ */
+public class ContextualEduStatsManager implements ResourceBasedOverride, SafeCloseable {
+    public static final MainThreadInitializedObject<ContextualEduStatsManager> INSTANCE =
+            forOverride(ContextualEduStatsManager.class, R.string.contextual_edu_manager_class);
+
+    /**
+     * Updates contextual education stats when a gesture is triggered
+     * @param isTrackpadGesture indicates if the gesture is triggered by trackpad
+     * @param gestureType type of gesture triggered
+     */
+    public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
+    }
+
+    @Override
+    public void close() {
+    }
+}
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 6311638..2276ac7 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -41,14 +42,13 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.apppairs.AppPairIconDrawingParams;
 import com.android.launcher3.apppairs.AppPairIconGraphic;
-import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
@@ -442,10 +442,8 @@
     @VisibleForTesting
     public void setDrawable(PreviewItemDrawingParams p, ItemInfo item) {
         if (item instanceof WorkspaceItemInfo wii) {
-            if (wii.hasPromiseIconUi() || (wii.runtimeStatusFlags
-                    & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
-                PreloadIconDrawable drawable = newPendingIcon(mContext, wii);
-                p.drawable = drawable;
+            if (isActivePendingIcon(wii)) {
+                p.drawable = newPendingIcon(mContext, wii);
             } else {
                 p.drawable = wii.newIcon(mContext,
                         Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
@@ -463,4 +461,14 @@
         // callback will be released when the folder is opened.
         p.drawable.setCallback(mIcon);
     }
+
+    /**
+     * Returns true if item is a Promise Icon or actively downloading, and the item is not an
+     * inactive archived app.
+     */
+    private boolean isActivePendingIcon(WorkspaceItemInfo item) {
+        return (item.hasPromiseIconUi()
+                || (item.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
+                && !(Flags.useNewIconForArchivedApps() && item.isInactiveArchive());
+    }
 }
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 480e8f3..ec0efe0 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -199,6 +199,10 @@
     }
 
     protected void changeFocus(T item, boolean hasFocus) {
+        if (mLastFocusedItem != item && !hasFocus) {
+            return;
+        }
+
         if (hasFocus) {
             endCurrentAnimation();
 
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 7e1d40d..da1a221 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -83,6 +83,7 @@
 
 import org.xmlpull.v1.XmlPullParser;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.StringReader;
 
@@ -104,10 +105,30 @@
         mContext = context;
     }
 
+    private void printDBs(String prefix) {
+        try {
+            File directory = new File(
+                    mContext.getDatabasePath(InvariantDeviceProfile.INSTANCE.get(mContext).dbFile)
+                            .getParent()
+            );
+            if (directory.exists()) {
+                for (File file : directory.listFiles()) {
+                    Log.d("b/353505773", prefix + "Database file: " + file.getName());
+                }
+            } else {
+                Log.d("b/353505773", prefix + "No files found in the database directory");
+            }
+        } catch (Exception e) {
+            Log.e("b/353505773", prefix + e.getMessage());
+        }
+    }
+
     private synchronized void createDbIfNotExists() {
         if (mOpenHelper == null) {
             mOpenHelper = createDatabaseHelper(false /* forMigration */);
+            printDBs("before: ");
             RestoreDbTask.restoreIfNeeded(mContext, this);
+            printDBs("after: ");
         }
     }
 
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 35064cf..c949ce6 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -89,7 +89,7 @@
         if (!WIDGETS_ENABLED) {
             return Collections.emptyMap();
         }
-        return mWidgetsByPackageItem;
+        return new HashMap<>(mWidgetsByPackageItem);
     }
 
     /**
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 40e3813..f31bf1e 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherSettings;
@@ -97,6 +98,8 @@
 
     public int options;
 
+    @Nullable
+    private ShortcutInfo mShortcutInfo = null;
 
     public WorkspaceItemInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
@@ -175,6 +178,9 @@
 
     public void updateFromDeepShortcutInfo(@NonNull final ShortcutInfo shortcutInfo,
             @NonNull final Context context) {
+        if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+            mShortcutInfo = shortcutInfo;
+        }
         // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent
         intent = ShortcutKey.makeIntent(shortcutInfo);
         title = shortcutInfo.getShortLabel();
@@ -204,6 +210,11 @@
             : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
     }
 
+    @Nullable
+    public ShortcutInfo getDeepShortcutInfo() {
+        return mShortcutInfo;
+    }
+
     /**
      * {@code true} if the shortcut is disabled due to its app being a lower version.
      */
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f7e1168..0c90eb9 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -11,9 +11,11 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Rect;
 import android.os.Process;
 import android.os.UserHandle;
+import android.util.Log;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
@@ -25,6 +27,7 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.AbstractFloatingViewHelper;
 import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.SecondaryDropTarget;
 import com.android.launcher3.Utilities;
@@ -53,6 +56,7 @@
  */
 public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
         implements View.OnClickListener {
+    private static final String TAG = "SystemShortcut";
 
     private final int mIconResId;
     protected final int mLabelResId;
@@ -383,4 +387,63 @@
         mAbstractFloatingViewHelper.closeOpenViews(mTarget, true,
                 AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
     }
+
+    public static final Factory<ActivityContext> BUBBLE_SHORTCUT =
+            (activity, itemInfo, originalView) -> {
+                if ((itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+                        && (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION)
+                        && !(itemInfo instanceof WorkspaceItemInfo)) {
+                    return null;
+                }
+                return new BubbleShortcut(activity, itemInfo, originalView);
+            };
+
+    public interface BubbleActivityStarter {
+        /** Tell SysUI to show the provided shortcut in a bubble. */
+        void showShortcutBubble(ShortcutInfo info);
+
+        /** Tell SysUI to show the provided intent in a bubble. */
+        void showAppBubble(Intent intent);
+    }
+
+    public static class BubbleShortcut<T extends ActivityContext> extends SystemShortcut<T> {
+
+        private BubbleActivityStarter mStarter;
+
+        public BubbleShortcut(T target, ItemInfo itemInfo, View originalView) {
+            super(R.drawable.ic_bubble_button, R.string.bubble, target,
+                    itemInfo, originalView);
+            if (target instanceof BubbleActivityStarter) {
+                mStarter = (BubbleActivityStarter) target;
+            }
+        }
+
+        @Override
+        public void onClick(View view) {
+            dismissTaskMenuView();
+            if (mStarter == null) {
+                Log.w(TAG, "starter null!");
+                return;
+            }
+            // TODO: handle GroupTask (single) items so that recent items in taskbar work
+            if (mItemInfo instanceof WorkspaceItemInfo) {
+                WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo;
+                ShortcutInfo shortcutInfo = workspaceItemInfo.getDeepShortcutInfo();
+                if (shortcutInfo != null) {
+                    mStarter.showShortcutBubble(shortcutInfo);
+                    return;
+                }
+            }
+            // If we're here check for an intent
+            Intent intent = mItemInfo.getIntent();
+            if (intent != null) {
+                if (intent.getPackage() == null) {
+                    intent.setPackage(mItemInfo.getTargetPackage());
+                }
+                mStarter.showAppBubble(intent);
+            } else {
+                Log.w(TAG, "unable to bubble, no intent: " + mItemInfo);
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index f895b30..6ff51ca 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -17,13 +17,12 @@
 package com.android.launcher3.recyclerview
 
 import android.content.Context
-import android.view.ViewGroup
-import androidx.annotation.VisibleForTesting
-import androidx.annotation.VisibleForTesting.Companion.PROTECTED
+import android.util.Log
 import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import com.android.launcher3.BubbleTextView
+import com.android.launcher3.BuildConfig
 import com.android.launcher3.allapps.BaseAllAppsAdapter
 import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.util.CancellableTask
@@ -41,18 +40,36 @@
  * [RecyclerView]. The view inflation will happen on background thread and inflated [ViewHolder]s
  * will be added to [RecycledViewPool] on main thread.
  */
-class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : ActivityContext {
+class AllAppsRecyclerViewPool<T> : RecycledViewPool() {
 
     var hasWorkProfile = false
-    @VisibleForTesting(otherwise = PROTECTED)
-    var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
+    private var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
+
+    companion object {
+        private const val TAG = "AllAppsRecyclerViewPool"
+        private const val NULL_LAYOUT_MANAGER_ERROR_STRING =
+            "activeRv's layoutManager should not be null"
+    }
 
     /**
      * Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
      */
-    fun preInflateAllAppsViewHolders(context: T) {
+    fun <T> preInflateAllAppsViewHolders(context: T) where T : Context, T : ActivityContext {
         val appsView = context.appsView ?: return
         val activeRv: RecyclerView = appsView.activeRecyclerView ?: return
+        val preInflateCount = getPreinflateCount(context)
+        if (preInflateCount <= 0) {
+            return
+        }
+
+        if (activeRv.layoutManager == null) {
+            if (BuildConfig.IS_STUDIO_BUILD) {
+                throw IllegalStateException(NULL_LAYOUT_MANAGER_ERROR_STRING)
+            } else {
+                Log.e(TAG, NULL_LAYOUT_MANAGER_ERROR_STRING)
+            }
+            return
+        }
 
         // Create a separate context dedicated for all apps preinflation thread. The goal is to
         // create a separate AssetManager obj internally to avoid lock contention with
@@ -81,47 +98,36 @@
                 override fun getLayoutManager(): RecyclerView.LayoutManager? = null
             }
 
-        preInflateAllAppsViewHolders(adapter, BaseAllAppsAdapter.VIEW_TYPE_ICON, activeRv) {
-            getPreinflateCount(context)
-        }
-    }
-
-    @VisibleForTesting(otherwise = PROTECTED)
-    fun preInflateAllAppsViewHolders(
-        adapter: RecyclerView.Adapter<*>,
-        viewType: Int,
-        parent: ViewGroup,
-        preInflationCountProvider: () -> Int
-    ) {
-        val preinflationCount = preInflationCountProvider.invoke()
-        if (preinflationCount <= 0) {
-            return
-        }
         mCancellableTask?.cancel()
         var task: CancellableTask<List<ViewHolder>>? = null
         task =
             CancellableTask(
                 {
                     val list: ArrayList<ViewHolder> = ArrayList()
-                    for (i in 0 until preinflationCount) {
+                    for (i in 0 until preInflateCount) {
                         if (task?.canceled == true) {
                             break
                         }
-                        list.add(adapter.createViewHolder(parent, viewType))
+                        // If activeRv's layout manager has been reset to null on main thread, skip
+                        // the preinflation as we cannot generate correct LayoutParams
+                        if (activeRv.layoutManager == null) {
+                            break
+                        }
+                        list.add(
+                            adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
+                        )
                     }
                     list
                 },
                 MAIN_EXECUTOR,
                 { viewHolders ->
-                    // Run preInflationCountProvider again as the needed VH might have changed
-                    val newPreinflationCount = preInflationCountProvider.invoke()
-                    for (i in 0 until minOf(viewHolders.size, newPreinflationCount)) {
+                    for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
                         putRecycledView(viewHolders[i])
                     }
                 }
             )
         mCancellableTask = task
-        VIEW_PREINFLATION_EXECUTOR.execute(mCancellableTask)
+        VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
     }
 
     /**
@@ -142,7 +148,7 @@
      * app icons in size of one all apps pages, so that opening all apps don't need to inflate app
      * icons.
      */
-    fun getPreinflateCount(context: T): Int {
+    fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
         var targetPreinflateCount =
             PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
                 EXTRA_ICONS_COUNT
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 63e919a..821dda7 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -31,7 +31,8 @@
     fun getTaskbarPhoneDimensions(
             deviceProfile: DeviceProfile,
             res: Resources,
-            isPhoneMode: Boolean
+            isPhoneMode: Boolean,
+            isGestureNav: Boolean,
     ): Point {
         val p = Point()
         // Taskbar for large screen
@@ -42,7 +43,7 @@
         }
 
         // Taskbar on phone using gesture nav, it will always be stashed
-        if (deviceProfile.isGestureMode) {
+        if (isGestureNav) {
             p.x = ViewGroup.LayoutParams.MATCH_PARENT
             p.y = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size)
             return p
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 95624b1..837d7bc 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -186,12 +186,6 @@
         public int stagePosition = STAGE_POSITION_UNDEFINED;
         @StageType
         public int stageType = STAGE_TYPE_UNDEFINED;
-
-        @Override
-        public String toString() {
-            return "SplitStageInfo { taskId=" + taskId
-                    + ", stagePosition=" + stagePosition + ", stageType=" + stageType + " }";
-        }
     }
 
     public static StatsLogManager.EventEnum getLogEventForPosition(@StagePosition int position) {
diff --git a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
new file mode 100644
index 0000000..e9691a8
--- /dev/null
+++ b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
@@ -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.util.coroutines
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+
+interface DispatcherProvider {
+    val default: CoroutineDispatcher
+    val io: CoroutineDispatcher
+    val main: CoroutineDispatcher
+    val unconfined: CoroutineDispatcher
+}
+
+object ProductionDispatchers : DispatcherProvider {
+    override val default: CoroutineDispatcher = Dispatchers.Default
+    override val io: CoroutineDispatcher = Dispatchers.IO
+    override val main: CoroutineDispatcher = Dispatchers.Main
+    override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined
+}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index bc66a33..ef66ffe 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -19,11 +19,19 @@
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
 import android.util.AttributeSet;
-import android.widget.TextView;
+import android.util.Log;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
@@ -45,22 +53,65 @@
 
     public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mShadowInfo = new ShadowInfo(context, attrs, defStyle);
-        setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
+        mShadowInfo = ShadowInfo.Companion.fromContext(context, attrs, defStyle);
+        setShadowLayer(
+                mShadowInfo.getAmbientShadowBlur(),
+                0,
+                0,
+                mShadowInfo.getAmbientShadowColor()
+        );
+    }
+
+    @Override
+    public void setTextWithStartIcon(CharSequence text, @DrawableRes int drawableId) {
+        Drawable drawable = getContext().getDrawable(drawableId);
+        if (drawable == null) {
+            setText(text);
+            Log.w(TAG, "setTextWithStartIcon: start icon Drawable not found from resources"
+                    + ", will just set text instead.");
+            return;
+        }
+        drawable.setTint(getCurrentTextColor());
+        int textSize = Math.round(getTextSize());
+        ImageSpan imageSpan;
+        if (!skipDoubleShadow() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            drawable = getDoubleShadowDrawable(drawable, textSize);
+        }
+        drawable.setBounds(0, 0, textSize, textSize);
+        imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_CENTER);
+        // First space will be replaced with Drawable, second space is for space before text.
+        SpannableString spannable = new SpannableString("  " + text);
+        spannable.setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+        setText(spannable);
+    }
+
+    @RequiresApi(Build.VERSION_CODES.S)
+    private DoubleShadowIconDrawable getDoubleShadowDrawable(
+            @NonNull Drawable drawable, int textSize
+    ) {
+        // add some padding via inset to avoid shadow clipping
+        int iconInsetSize = getContext().getResources()
+                .getDimensionPixelSize(R.dimen.app_title_icon_shadow_inset);
+        return new DoubleShadowIconDrawable(
+                mShadowInfo,
+                drawable,
+                textSize,
+                iconInsetSize
+        );
     }
 
     @Override
     public void onDraw(Canvas canvas) {
         // If text is transparent or shadow alpha is 0, don't draw any shadow
-        if (mShadowInfo.skipDoubleShadow(this)) {
+        if (skipDoubleShadow()) {
             super.onDraw(canvas);
             return;
         }
         int alpha = Color.alpha(getCurrentTextColor());
 
         // We enhance the shadow by drawing the shadow twice
-        getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
-                getTextShadowColor(mShadowInfo.ambientShadowColor, alpha));
+        getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
+                getTextShadowColor(mShadowInfo.getAmbientShadowColor(), alpha));
 
         drawWithoutDot(canvas);
         canvas.save();
@@ -69,10 +120,10 @@
                 getScrollY() + getHeight());
 
         getPaint().setShadowLayer(
-                mShadowInfo.keyShadowBlur,
-                mShadowInfo.keyShadowOffsetX,
-                mShadowInfo.keyShadowOffsetY,
-                getTextShadowColor(mShadowInfo.keyShadowColor, alpha));
+                mShadowInfo.getKeyShadowBlur(),
+                mShadowInfo.getKeyShadowOffsetX(),
+                mShadowInfo.getKeyShadowOffsetY(),
+                getTextShadowColor(mShadowInfo.getKeyShadowColor(), alpha));
         drawWithoutDot(canvas);
         canvas.restore();
 
@@ -80,55 +131,30 @@
         drawRunningAppIndicatorIfNecessary(canvas);
     }
 
-    public static class ShadowInfo {
-        public final float ambientShadowBlur;
-        public final int ambientShadowColor;
-
-        public final float keyShadowBlur;
-        public final float keyShadowOffsetX;
-        public final float keyShadowOffsetY;
-        public final int keyShadowColor;
-
-        public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
-
-            TypedArray a = c.obtainStyledAttributes(
-                    attrs, R.styleable.ShadowInfo, defStyle, 0);
-
-            ambientShadowBlur = a.getDimensionPixelSize(
-                    R.styleable.ShadowInfo_ambientShadowBlur, 0);
-            ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
-
-            keyShadowBlur = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0);
-            keyShadowOffsetX = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0);
-            keyShadowOffsetY = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0);
-            keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
-            a.recycle();
-        }
-
-        public boolean skipDoubleShadow(TextView textView) {
-            int textAlpha = Color.alpha(textView.getCurrentTextColor());
-            int keyShadowAlpha = Color.alpha(keyShadowColor);
-            int ambientShadowAlpha = Color.alpha(ambientShadowColor);
-            if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
-                textView.getPaint().clearShadowLayer();
-                return true;
-            } else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
-                textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
-                        getTextShadowColor(ambientShadowColor, textAlpha));
-                return true;
-            } else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
-                textView.getPaint().setShadowLayer(
-                        keyShadowBlur,
-                        keyShadowOffsetX,
-                        keyShadowOffsetY,
-                        getTextShadowColor(keyShadowColor, textAlpha));
-                return true;
-            } else {
-                return false;
-            }
+    private boolean skipDoubleShadow() {
+        int textAlpha = Color.alpha(getCurrentTextColor());
+        int keyShadowAlpha = Color.alpha(mShadowInfo.getKeyShadowColor());
+        int ambientShadowAlpha = Color.alpha(mShadowInfo.getAmbientShadowColor());
+        if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
+            getPaint().clearShadowLayer();
+            return true;
+        } else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
+            getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
+                    getTextShadowColor(mShadowInfo.getAmbientShadowColor(), textAlpha));
+            return true;
+        } else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
+            getPaint().setShadowLayer(
+                    mShadowInfo.getKeyShadowBlur(),
+                    mShadowInfo.getKeyShadowOffsetX(),
+                    mShadowInfo.getKeyShadowOffsetY(),
+                    getTextShadowColor(mShadowInfo.getKeyShadowColor(), textAlpha));
+            return true;
+        } else {
+            return false;
         }
     }
 
+
     // Multiplies the alpha of shadowColor by textAlpha.
     private static int getTextShadowColor(int shadowColor, int textAlpha) {
         return setColorAlphaBound(shadowColor,
diff --git a/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt b/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt
new file mode 100644
index 0000000..7ac7c94
--- /dev/null
+++ b/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.views
+
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.InsetDrawable
+import android.os.Build.VERSION_CODES
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+
+/**
+ * Launcher wrapper for Drawables to provide a double shadow effect. Currently for use with
+ * [DoubleShadowBubbleTextView] to provide a similar shadow to inline icons.
+ */
+@RequiresApi(VERSION_CODES.S)
+class DoubleShadowIconDrawable(
+    private val shadowInfo: ShadowInfo,
+    iconDrawable: Drawable,
+    private val iconSize: Int,
+    iconInsetSize: Int
+) : Drawable() {
+    private val mIconDrawable: InsetDrawable
+    private val mDoubleShadowNode: RenderNode?
+
+    init {
+        mIconDrawable = InsetDrawable(iconDrawable, iconInsetSize)
+        mIconDrawable.setBounds(0, 0, iconSize, iconSize)
+        mDoubleShadowNode = createShadowRenderNode()
+    }
+
+    @VisibleForTesting
+    fun createShadowRenderNode(): RenderNode {
+        val renderNode = RenderNode("DoubleShadowNode")
+        renderNode.setPosition(0, 0, iconSize, iconSize)
+        // Create render effects
+        val ambientShadow =
+            createShadowRenderEffect(
+                shadowInfo.ambientShadowBlur,
+                0f,
+                0f,
+                Color.alpha(shadowInfo.ambientShadowColor).toFloat()
+            )
+        val keyShadow =
+            createShadowRenderEffect(
+                shadowInfo.keyShadowBlur,
+                shadowInfo.keyShadowOffsetX,
+                shadowInfo.keyShadowOffsetY,
+                Color.alpha(shadowInfo.keyShadowColor).toFloat()
+            )
+        val blend = RenderEffect.createBlendModeEffect(ambientShadow, keyShadow, BlendMode.DST_ATOP)
+        renderNode.setRenderEffect(blend)
+        return renderNode
+    }
+
+    @VisibleForTesting
+    fun createShadowRenderEffect(
+        radius: Float,
+        offsetX: Float,
+        offsetY: Float,
+        alpha: Float
+    ): RenderEffect {
+        return RenderEffect.createColorFilterEffect(
+            PorterDuffColorFilter(Color.argb(alpha, 0f, 0f, 0f), PorterDuff.Mode.MULTIPLY),
+            RenderEffect.createOffsetEffect(
+                offsetX,
+                offsetY,
+                RenderEffect.createBlurEffect(radius, radius, Shader.TileMode.CLAMP)
+            )
+        )
+    }
+
+    override fun draw(canvas: Canvas) {
+        if (canvas.isHardwareAccelerated && mDoubleShadowNode != null) {
+            if (!mDoubleShadowNode.hasDisplayList()) {
+                // Record render node if its display list is not recorded or discarded
+                // (which happens when it's no longer drawn by anything).
+                val recordingCanvas = mDoubleShadowNode.beginRecording()
+                mIconDrawable.draw(recordingCanvas)
+                mDoubleShadowNode.endRecording()
+            }
+            canvas.drawRenderNode(mDoubleShadowNode)
+        }
+        mIconDrawable.draw(canvas)
+    }
+
+    override fun getIntrinsicHeight() = iconSize
+
+    override fun getIntrinsicWidth() = iconSize
+
+    override fun getOpacity() = PixelFormat.TRANSPARENT
+
+    override fun setAlpha(alpha: Int) {
+        mIconDrawable.alpha = alpha
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        mIconDrawable.colorFilter = colorFilter
+    }
+
+    override fun setTint(color: Int) {
+        mIconDrawable.setTint(color)
+    }
+
+    override fun setTintList(tint: ColorStateList?) {
+        mIconDrawable.setTintList(tint)
+    }
+}
diff --git a/src/com/android/launcher3/views/ShadowInfo.kt b/src/com/android/launcher3/views/ShadowInfo.kt
new file mode 100644
index 0000000..4f626ec
--- /dev/null
+++ b/src/com/android/launcher3/views/ShadowInfo.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.views
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.launcher3.R
+
+/**
+ * Launcher data holder for classes such as [DoubleShadowBubbleTextView] to model shadows for
+ * "double shadow" effect.
+ */
+data class ShadowInfo(
+    val ambientShadowBlur: Float,
+    val ambientShadowColor: Int,
+    val keyShadowBlur: Float,
+    val keyShadowOffsetX: Float,
+    val keyShadowOffsetY: Float,
+    val keyShadowColor: Int
+) {
+
+    companion object {
+        /** Constructs instance of ShadowInfo from Context and given attribute set. */
+        @JvmStatic
+        fun fromContext(context: Context, attrs: AttributeSet?, defStyle: Int): ShadowInfo {
+            val styledAttrs =
+                context.obtainStyledAttributes(attrs, R.styleable.ShadowInfo, defStyle, 0)
+            val shadowInfo =
+                ShadowInfo(
+                    ambientShadowBlur =
+                        styledAttrs
+                            .getDimensionPixelSize(R.styleable.ShadowInfo_ambientShadowBlur, 0)
+                            .toFloat(),
+                    ambientShadowColor =
+                        styledAttrs.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0),
+                    keyShadowBlur =
+                        styledAttrs
+                            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0)
+                            .toFloat(),
+                    keyShadowOffsetX =
+                        styledAttrs
+                            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0)
+                            .toFloat(),
+                    keyShadowOffsetY =
+                        styledAttrs
+                            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0)
+                            .toFloat(),
+                    keyShadowColor = styledAttrs.getColor(R.styleable.ShadowInfo_keyShadowColor, 0)
+                )
+            styledAttrs.recycle()
+            return shadowInfo
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index 71d8503..91b899c 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -24,6 +24,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.util.Executors;
@@ -77,6 +78,11 @@
         mViewToRecycle = viewToRecycle;
     }
 
+    @VisibleForTesting
+    @Nullable ListenableHostView getViewToRecycle() {
+        return mViewToRecycle;
+    }
+
     @Override
     @NonNull
     public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
diff --git a/tests/Android.bp b/tests/Android.bp
index e51242f..c99f656 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -71,6 +71,9 @@
 // Library with all the dependencies for building quickstep
 android_library {
     name: "Launcher3TestLib",
+    defaults: [
+        "launcher_compose_tests_defaults",
+    ],
     srcs: [],
     asset_dirs: ["assets"],
     resource_dirs: ["res"],
@@ -112,6 +115,9 @@
 
 android_test {
     name: "Launcher3Tests",
+    defaults: [
+        "launcher_compose_tests_defaults",
+    ],
     srcs: [
         ":launcher-tests-src",
         ":launcher-non-quickstep-tests-src",
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 dc3b321..3f4a73a 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -173,8 +173,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 PRIVATE_SPACE_SCROLL_FAILURE = "b/339737008";
-
     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/HotseatReorderUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
index c32461e..a3c7f4f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -104,7 +104,7 @@
         val cl = cellLayoutBuilder.createCellLayout(board.width, board.height, false)
         // The views have to be sorted or the result can vary
         board.icons
-            .map(IconPoint::getCoord)
+            .map(IconPoint::coord)
             .sortedWith(
                 Comparator.comparing { p: Any -> (p as Point).x }
                     .thenComparing { p: Any -> (p as Point).y }
@@ -120,9 +120,7 @@
                 )
             }
         board.widgets
-            .sortedWith(
-                Comparator.comparing(WidgetRect::getCellX).thenComparing(WidgetRect::getCellY)
-            )
+            .sortedWith(Comparator.comparing(WidgetRect::cellX).thenComparing(WidgetRect::cellY))
             .forEach { widget ->
                 addViewInCellLayout(
                     cl,
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt
new file mode 100644
index 0000000..3cbfc5a
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.board
+
+import android.graphics.Point
+import android.graphics.Rect
+
+/** Represents a widget in a CellLayoutBoard */
+data class WidgetRect(
+    val type: Char,
+    val bounds: Rect,
+) {
+    val spanX: Int = bounds.right - bounds.left + 1
+    val spanY: Int = bounds.top - bounds.bottom + 1
+    val cellY: Int = bounds.bottom
+    val cellX: Int = bounds.left
+
+    fun shouldIgnore() = type == CellType.IGNORE
+
+    fun contains(x: Int, y: Int) = bounds.contains(x, y)
+}
+
+/**
+ * [A-Z]: Represents a folder and number of icons in the folder is represented by the order of
+ * letter in the alphabet, A=2, B=3, C=4 ... etc.
+ */
+data class FolderPoint(val coord: Point, val type: Char) {
+    val numberIconsInside: Int = type.code - 'A'.code + 2
+}
+
+/** Represents an icon in a CellLayoutBoard */
+data class IconPoint(val coord: Point, val type: Char = CellType.ICON)
+
+object CellType {
+    // The cells marked by this will be filled by 1x1 widgets and will be ignored when
+    // validating
+    const val IGNORE = 'x'
+
+    // The cells marked by this will be filled by app icons
+    const val ICON = 'i'
+
+    // The cells marked by FOLDER will be filled by folders with 27 app icons inside
+    const val FOLDER = 'Z'
+
+    // Empty space
+    const val EMPTY = '-'
+
+    // Widget that will be saved as "main widget" for easier retrieval
+    const val MAIN_WIDGET = 'm' // Everything else will be consider a widget
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
index e5ad888..04bfee9 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
@@ -88,7 +88,7 @@
 
     public WidgetRect getWidgetOfType(char type) {
         return mWidgetsRects.stream()
-                .filter(widgetRect -> widgetRect.mType == type).findFirst().orElse(null);
+                .filter(widgetRect -> widgetRect.getType() == type).findFirst().orElse(null);
     }
 
     public WidgetRect getWidgetAt(int x, int y) {
@@ -117,8 +117,8 @@
     }
 
     private void removeWidgetFromBoard(WidgetRect widget) {
-        for (int xi = widget.mBounds.left; xi <= widget.mBounds.right; xi++) {
-            for (int yi = widget.mBounds.bottom; yi <= widget.mBounds.top; yi++) {
+        for (int xi = widget.getBounds().left; xi <= widget.getBounds().right; xi++) {
+            for (int yi = widget.getBounds().bottom; yi <= widget.getBounds().top; yi++) {
                 mWidget[xi][yi] = '-';
             }
         }
@@ -127,7 +127,7 @@
     private void removeOverlappingItems(Rect rect) {
         // Remove overlapping widgets and remove them from the board
         mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
-            if (rect.intersect(widget.mBounds)) {
+            if (rect.intersect(widget.getBounds())) {
                 removeWidgetFromBoard(widget);
                 return false;
             }
@@ -135,8 +135,8 @@
         }).collect(Collectors.toList());
         // Remove overlapping icons and remove them from the board
         mIconPoints = mIconPoints.stream().filter(iconPoint -> {
-            int x = iconPoint.coord.x;
-            int y = iconPoint.coord.y;
+            int x = iconPoint.getCoord().x;
+            int y = iconPoint.getCoord().y;
             if (rect.contains(x, y)) {
                 mWidget[x][y] = '-';
                 return false;
@@ -146,8 +146,8 @@
 
         // Remove overlapping folders and remove them from the board
         mFolderPoints = mFolderPoints.stream().filter(folderPoint -> {
-            int x = folderPoint.coord.x;
-            int y = folderPoint.coord.y;
+            int x = folderPoint.getCoord().x;
+            int y = folderPoint.getCoord().y;
             if (rect.contains(x, y)) {
                 mWidget[x][y] = '-';
                 return false;
@@ -159,7 +159,7 @@
     private void removeOverlappingItems(Point p) {
         // Remove overlapping widgets and remove them from the board
         mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
-            if (IdenticalBoardComparator.Companion.touchesPoint(widget.mBounds, p)) {
+            if (IdenticalBoardComparator.Companion.touchesPoint(widget.getBounds(), p)) {
                 removeWidgetFromBoard(widget);
                 return false;
             }
@@ -167,8 +167,8 @@
         }).collect(Collectors.toList());
         // Remove overlapping icons and remove them from the board
         mIconPoints = mIconPoints.stream().filter(iconPoint -> {
-            int x = iconPoint.coord.x;
-            int y = iconPoint.coord.y;
+            int x = iconPoint.getCoord().x;
+            int y = iconPoint.getCoord().y;
             if (p.x == x && p.y == y) {
                 mWidget[x][y] = '-';
                 return false;
@@ -178,8 +178,8 @@
 
         // Remove overlapping folders and remove them from the board
         mFolderPoints = mFolderPoints.stream().filter(folderPoint -> {
-            int x = folderPoint.coord.x;
-            int y = folderPoint.coord.y;
+            int x = folderPoint.getCoord().x;
+            int y = folderPoint.getCoord().y;
             if (p.x == x && p.y == y) {
                 mWidget[x][y] = '-';
                 return false;
@@ -226,7 +226,7 @@
 
     public void removeItem(char type) {
         mWidgetsRects.stream()
-                .filter(widgetRect -> widgetRect.mType == type)
+                .filter(widgetRect -> widgetRect.getType() == type)
                 .forEach(widgetRect -> removeOverlappingItems(
                         new Point(widgetRect.getCellX(), widgetRect.getCellY())));
     }
@@ -365,10 +365,10 @@
         board.mWidth = lines[0].length();
         board.mWidgetsRects = getRects(board.mWidget);
         board.mWidgetsRects.forEach(widgetRect -> {
-            if (widgetRect.mType == CellType.MAIN_WIDGET) {
+            if (widgetRect.getType() == CellType.MAIN_WIDGET) {
                 board.mMain = widgetRect;
             }
-            board.mWidgetsMap.put(widgetRect.mType, widgetRect);
+            board.mWidgetsMap.put(widgetRect.getType(), widgetRect);
         });
         board.mIconPoints = getIconPoints(board.mWidget);
         board.mFolderPoints = getFolderPoints(board.mWidget);
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
deleted file mode 100644
index 49c146b..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-public class CellType {
-    // The cells marked by this will be filled by 1x1 widgets and will be ignored when
-    // validating
-    public static final char IGNORE = 'x';
-    // The cells marked by this will be filled by app icons
-    public static final char ICON = 'i';
-    // The cells marked by FOLDER will be filled by folders with 27 app icons inside
-    public static final char FOLDER = 'Z';
-    // Empty space
-    public static final char EMPTY = '-';
-    // Widget that will be saved as "main widget" for easier retrieval
-    public static final char MAIN_WIDGET = 'm';
-    // Everything else will be consider a widget
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
deleted file mode 100644
index 39ba434..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Point;
-
-public class FolderPoint {
-    public Point coord;
-    public char mType;
-
-    public FolderPoint(Point coord, char type) {
-        this.coord = coord;
-        mType = type;
-    }
-
-    /**
-     * [A-Z]: Represents a folder and number of icons in the folder is represented by
-     * the order of letter in the alphabet, A=2, B=3, C=4 ... etc.
-     */
-    public int getNumberIconsInside() {
-        return (mType - 'A') + 2;
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
deleted file mode 100644
index d3d2970..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Point;
-
-public class IconPoint {
-    public Point coord;
-    public char mType;
-
-    public IconPoint(Point coord, char type) {
-        this.coord = coord;
-        mType = type;
-    }
-
-    public char getType() {
-        return mType;
-    }
-
-    public void setType(char type) {
-        mType = type;
-    }
-
-    public Point getCoord() {
-        return coord;
-    }
-
-    public void setCoord(Point coord) {
-        this.coord = coord;
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
index a4a420c..aacd940 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
@@ -26,11 +26,11 @@
 
     /** Converts a list of WidgetRect into a map of the count of different widget.bounds */
     private fun widgetsToBoundsMap(widgets: List<WidgetRect>) =
-        widgets.groupingBy { it.mBounds }.eachCount()
+        widgets.groupingBy { it.bounds }.eachCount()
 
     /** Converts a list of IconPoint into a map of the count of different icon.coord */
     private fun iconsToPosCountMap(widgets: List<IconPoint>) =
-        widgets.groupingBy { it.getCoord() }.eachCount()
+        widgets.groupingBy { it.coord }.eachCount()
 
     override fun compare(
         cellLayoutBoard: CellLayoutBoard,
@@ -47,7 +47,7 @@
             widgetsToBoundsMap(
                 otherCellLayoutBoard.widgets
                     .filter { !it.shouldIgnore() }
-                    .filter { !overlapsWithIgnored(ignoredRectangles, it.mBounds) }
+                    .filter { !overlapsWithIgnored(ignoredRectangles, it.bounds) }
             )
 
         if (widgetsMap != otherWidgetMap) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
deleted file mode 100644
index 8a427dd..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.celllayout.board;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.ui.TestViewHelpers.findWidgetProvider;
-import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Process;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-
-import java.util.function.Supplier;
-import java.util.stream.IntStream;
-
-public class TestWorkspaceBuilder {
-
-    private static final String TAG = "CellLayoutBoardBuilder";
-    private static final String TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests.";
-    private ComponentName mAppComponentName = new ComponentName(
-            "com.google.android.calculator", "com.android.calculator2.Calculator");
-    private UserHandle mMyUser;
-
-    private Context mContext;
-
-    public TestWorkspaceBuilder(Context context) {
-        mMyUser = Process.myUserHandle();
-        mContext = context;
-    }
-
-    /**
-     * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
-     */
-    private FavoriteItemsTransaction fillWithWidgets(WidgetRect widgetRect,
-            FavoriteItemsTransaction transaction, int screenId) {
-        int initX = widgetRect.getCellX();
-        int initY = widgetRect.getCellY();
-        for (int x = initX; x < initX + widgetRect.getSpanX(); x++) {
-            for (int y = initY; y < initY + widgetRect.getSpanY(); y++) {
-                try {
-                    // this widgets are filling, we don't care if we can't place them
-                    transaction.addItem(createWidgetInCell(
-                            new WidgetRect(CellType.IGNORE,
-                                    new Rect(x, y, x, y)), screenId));
-                } catch (Exception e) {
-                    Log.d(TAG, "Unable to place filling widget at " + x + "," + y);
-                }
-            }
-        }
-        return transaction;
-    }
-
-    private AppInfo getApp() {
-        return new AppInfo(mAppComponentName, "test icon", mMyUser,
-                AppInfo.makeLaunchIntent(mAppComponentName));
-    }
-
-    /**
-     * Helper to set the app to use for the test workspace,
-     *  using activity-alias from AndroidManifest-common.
-     * @param testAppName the android:name field of the test app activity-alias to use
-     */
-    public void setTestAppActivityAlias(String testAppName) {
-        this.mAppComponentName = new ComponentName(
-            getInstrumentation().getContext().getPackageName(),
-        TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
-        );
-    }
-
-    private void addCorrespondingWidgetRect(WidgetRect widgetRect,
-            FavoriteItemsTransaction transaction, int screenId) {
-        if (widgetRect.mType == 'x') {
-            fillWithWidgets(widgetRect, transaction, screenId);
-        } else {
-            transaction.addItem(createWidgetInCell(widgetRect, screenId));
-        }
-    }
-
-    /**
-     * Builds the given board into the transaction
-     */
-    public FavoriteItemsTransaction buildFromBoard(CellLayoutBoard board,
-            FavoriteItemsTransaction transaction, final int screenId) {
-        board.getWidgets().forEach(
-                (widgetRect) -> addCorrespondingWidgetRect(widgetRect, transaction, screenId));
-        board.getIcons().forEach((iconPoint) ->
-                transaction.addItem(() -> createIconInCell(iconPoint, screenId))
-        );
-        board.getFolders().forEach((folderPoint) ->
-                transaction.addItem(() -> createFolderInCell(folderPoint, screenId))
-        );
-        return transaction;
-    }
-
-    /**
-     * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
-     * be clean otherwise this doesn't overrides the existing icons.
-     */
-    public FavoriteItemsTransaction fillHotseatIcons(FavoriteItemsTransaction transaction) {
-        IntStream.range(0, InvariantDeviceProfile.INSTANCE.get(mContext).numDatabaseHotseatIcons)
-                .forEach(i -> transaction.addItem(() -> getHotseatValues(i)));
-        return transaction;
-    }
-
-    private Supplier<ItemInfo> createWidgetInCell(
-            WidgetRect widgetRect, int screenId) {
-        // Create the widget lazily since the appWidgetId can get lost during setup
-        return () -> {
-            LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
-            LauncherAppWidgetInfo item = createWidgetInfo(info, getApplicationContext(), true);
-            item.cellX = widgetRect.getCellX();
-            item.cellY = widgetRect.getCellY();
-            item.spanX = widgetRect.getSpanX();
-            item.spanY = widgetRect.getSpanY();
-            item.screenId = screenId;
-            return item;
-        };
-    }
-
-    public FolderInfo createFolderInCell(FolderPoint folderPoint, int screenId) {
-        FolderInfo folderInfo = new FolderInfo();
-        folderInfo.screenId = screenId;
-        folderInfo.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
-        folderInfo.cellX = folderPoint.coord.x;
-        folderInfo.cellY = folderPoint.coord.y;
-        folderInfo.minSpanY = folderInfo.minSpanX = folderInfo.spanX = folderInfo.spanY = 1;
-        folderInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null);
-
-        for (int i = 0; i < folderPoint.getNumberIconsInside(); i++) {
-            folderInfo.add(getDefaultWorkspaceItem(screenId), false);
-        }
-
-        return folderInfo;
-    }
-
-    private WorkspaceItemInfo getDefaultWorkspaceItem(int screenId) {
-        WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
-        item.screenId = screenId;
-        item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
-        item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
-        return item;
-    }
-
-    private ItemInfo createIconInCell(IconPoint iconPoint, int screenId) {
-        WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
-        item.screenId = screenId;
-        item.cellX = iconPoint.getCoord().x;
-        item.cellY = iconPoint.getCoord().y;
-        item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
-        item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
-        return item;
-    }
-
-    private ItemInfo getHotseatValues(int x) {
-        WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
-        item.cellX = x;
-        item.cellY = 0;
-        item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
-        item.rank = x;
-        item.screenId = x;
-        item.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
-        return item;
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
new file mode 100644
index 0000000..8952b85
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.board
+
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.Rect
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.celllayout.FavoriteItemsTransaction
+import com.android.launcher3.model.data.AppInfo
+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.ui.TestViewHelpers
+import com.android.launcher3.util.WidgetUtils
+import java.util.function.Supplier
+
+class TestWorkspaceBuilder(private val mContext: Context) {
+
+    private var appComponentName =
+        ComponentName("com.google.android.calculator", "com.android.calculator2.Calculator")
+    private val myUser: UserHandle = Process.myUserHandle()
+
+    /** Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases. */
+    private fun fillWithWidgets(
+        widgetRect: WidgetRect,
+        transaction: FavoriteItemsTransaction,
+        screenId: Int
+    ): FavoriteItemsTransaction {
+        val initX = widgetRect.cellX
+        val initY = widgetRect.cellY
+        for (x in initX until initX + widgetRect.spanX) {
+            for (y in initY until initY + widgetRect.spanY) {
+                try {
+                    // this widgets are filling, we don't care if we can't place them
+                    transaction.addItem(
+                        createWidgetInCell(WidgetRect(CellType.IGNORE, Rect(x, y, x, y)), screenId)
+                    )
+                } catch (e: Exception) {
+                    Log.d(TAG, "Unable to place filling widget at $x,$y")
+                }
+            }
+        }
+        return transaction
+    }
+
+    private fun app() =
+        AppInfo(appComponentName, "test icon", myUser, AppInfo.makeLaunchIntent(appComponentName))
+
+    /**
+     * Helper to set the app to use for the test workspace, using activity-alias from
+     * AndroidManifest-common.
+     *
+     * @param testAppName the android:name field of the test app activity-alias to use
+     */
+    fun setTestAppActivityAlias(testAppName: String) {
+        appComponentName =
+            ComponentName(
+                InstrumentationRegistry.getInstrumentation().context.packageName,
+                TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
+            )
+    }
+
+    private fun addCorrespondingWidgetRect(
+        widgetRect: WidgetRect,
+        transaction: FavoriteItemsTransaction,
+        screenId: Int
+    ) {
+        if (widgetRect.type == 'x') {
+            fillWithWidgets(widgetRect, transaction, screenId)
+        } else {
+            transaction.addItem(createWidgetInCell(widgetRect, screenId))
+        }
+    }
+
+    /** Builds the given board into the transaction */
+    fun buildFromBoard(
+        board: CellLayoutBoard,
+        transaction: FavoriteItemsTransaction,
+        screenId: Int
+    ): FavoriteItemsTransaction {
+        board.widgets.forEach { addCorrespondingWidgetRect(it, transaction, screenId) }
+        board.icons.forEach { transaction.addItem { createIconInCell(it, screenId) } }
+        board.folders.forEach { transaction.addItem { createFolderInCell(it, screenId) } }
+        return transaction
+    }
+
+    /**
+     * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
+     * be clean otherwise this doesn't overrides the existing icons.
+     */
+    fun fillHotseatIcons(transaction: FavoriteItemsTransaction): FavoriteItemsTransaction {
+        for (i in 0..<InvariantDeviceProfile.INSTANCE[mContext].numDatabaseHotseatIcons) {
+            transaction.addItem { getHotseatValues(i) }
+        }
+        return transaction
+    }
+
+    private fun createWidgetInCell(widgetRect: WidgetRect, paramScreenId: Int): Supplier<ItemInfo> {
+        // Create the widget lazily since the appWidgetId can get lost during setup
+        return Supplier<ItemInfo> {
+            WidgetUtils.createWidgetInfo(
+                    TestViewHelpers.findWidgetProvider(false),
+                    ApplicationProvider.getApplicationContext(),
+                    true
+                )
+                .apply {
+                    cellX = widgetRect.cellX
+                    cellY = widgetRect.cellY
+                    spanX = widgetRect.spanX
+                    spanY = widgetRect.spanY
+                    screenId = paramScreenId
+                }
+        }
+    }
+
+    fun createFolderInCell(folderPoint: FolderPoint, paramScreenId: Int): FolderInfo =
+        FolderInfo().apply {
+            screenId = paramScreenId
+            container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+            cellX = folderPoint.coord.x
+            cellY = folderPoint.coord.y
+            spanY = 1
+            spanX = 1
+            minSpanX = 1
+            minSpanY = 1
+            setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null)
+            for (i in 0 until folderPoint.numberIconsInside) {
+                add(getDefaultWorkspaceItem(paramScreenId), false)
+            }
+        }
+
+    private fun getDefaultWorkspaceItem(paramScreenId: Int): WorkspaceItemInfo =
+        WorkspaceItemInfo(app()).apply {
+            screenId = paramScreenId
+            spanY = 1
+            spanX = 1
+            minSpanX = 1
+            minSpanY = 1
+            container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+        }
+
+    private fun createIconInCell(iconPoint: IconPoint, paramScreenId: Int) =
+        WorkspaceItemInfo(app()).apply {
+            screenId = paramScreenId
+            cellX = iconPoint.coord.x
+            cellY = iconPoint.coord.y
+            spanY = 1
+            spanX = 1
+            minSpanX = 1
+            minSpanY = 1
+            container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+        }
+
+    private fun getHotseatValues(x: Int) =
+        WorkspaceItemInfo(app()).apply {
+            cellX = x
+            cellY = 0
+            spanY = 1
+            spanX = 1
+            minSpanX = 1
+            minSpanY = 1
+            rank = x
+            screenId = x
+            container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+        }
+
+    companion object {
+        private const val TAG = "CellLayoutBoardBuilder"
+        private const val TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests."
+    }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
deleted file mode 100644
index c90ce85..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Rect;
-
-public class WidgetRect {
-    public char mType;
-    public Rect mBounds;
-
-    public WidgetRect(char type, Rect bounds) {
-        this.mType = type;
-        this.mBounds = bounds;
-    }
-
-    public int getSpanX() {
-        return mBounds.right - mBounds.left + 1;
-    }
-
-    public int getSpanY() {
-        return mBounds.top - mBounds.bottom + 1;
-    }
-
-    public int getCellX() {
-        return mBounds.left;
-    }
-
-    public int getCellY() {
-        return mBounds.bottom;
-    }
-
-    boolean shouldIgnore() {
-        return this.mType == CellType.IGNORE;
-    }
-
-    boolean contains(int x, int y) {
-        return mBounds.contains(x, y);
-    }
-
-    @Override
-    public String toString() {
-        return "WidgetRect type = " + mType + " x = " + getCellX() + " | y " + getCellY()
-                + " xs = " + getSpanX() + " ys = " + getSpanY();
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
new file mode 100644
index 0000000..e27926f
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.icons
+
+import android.content.ComponentName
+import android.content.pm.PackageInfo
+import android.database.Cursor
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.icons.cache.BaseIconCache
+import com.android.launcher3.icons.cache.CachingLogic
+import com.android.launcher3.icons.cache.IconCacheUpdateHandler
+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.doReturn
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconCacheUpdateHandlerTest {
+
+    @Mock private lateinit var cursor: Cursor
+    @Mock private lateinit var user: UserHandle
+    @Mock private lateinit var cachingLogic: CachingLogic<String>
+    @Mock private lateinit var baseIconCache: BaseIconCache
+
+    private var componentMap: HashMap<ComponentName, String> = hashMapOf()
+    private var ignorePackages: Set<String> = setOf()
+    private var packageInfoMap: HashMap<String, PackageInfo> = hashMapOf()
+
+    private val dummyRowData =
+        IconCacheRowData(
+            "com.android.fake/.FakeActivity",
+            System.currentTimeMillis(),
+            1,
+            1.0.toLong(),
+            "stateOfConfusion"
+        )
+
+    @Before
+    fun setup() {
+
+        MockitoAnnotations.initMocks(this)
+        // Load in a specific row to the database
+        doReturn(0).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_COMPONENT)
+        doReturn(1).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_LAST_UPDATED)
+        doReturn(2).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_VERSION)
+        doReturn(3).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_ROWID)
+        doReturn(4).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_SYSTEM_STATE)
+        doReturn(dummyRowData.component).`when`(cursor).getString(0)
+        doReturn(dummyRowData.lastUpdated).`when`(cursor).getLong(1)
+        doReturn(dummyRowData.version).`when`(cursor).getInt(2)
+        doReturn(dummyRowData.row).`when`(cursor).getLong(3)
+        doReturn(dummyRowData.systemState).`when`(cursor).getString(4)
+    }
+
+    @Test
+    fun `IconCacheUpdateHandler returns null if the component name is malformed`() {
+        val updateHandlerUnderTest = IconCacheUpdateHandler(packageInfoMap, baseIconCache)
+
+        val result =
+            updateHandlerUnderTest.updateOrDeleteIcon(
+                cursor,
+                componentMap,
+                ignorePackages,
+                user,
+                cachingLogic
+            )
+
+        assert(result == null)
+    }
+}
+
+data class IconCacheRowData(
+    val component: String,
+    val lastUpdated: Long,
+    val version: Int,
+    val row: Long,
+    val systemState: String
+)
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
index 71f7d47..ff545fe 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
@@ -186,6 +186,35 @@
         assertThat(underTest.widgetsByComponentKey).isEmpty()
     }
 
+    @Test
+    fun getWidgetsByPackageItem_returnsACopyOfMap() {
+        loadWidgets()
+
+        val latch = CountDownLatch(1)
+        Executors.MODEL_EXECUTOR.execute {
+            var update = true
+
+            // each "widgetsByPackageItem" read returns a different copy of the map held internally.
+            // Modifying one shouldn't impact another.
+            for ((_, _) in underTest.widgetsByPackageItem.entries) {
+                underTest.widgetsByPackageItem.clear()
+                if (update) { // trigger update
+                    update = false
+                    // Similarly, model could update its code independently while a client is
+                    // iterating on the list.
+                    underTest.update(app, /* packageUser= */ null)
+                }
+            }
+
+            latch.countDown()
+        }
+        if (!latch.await(LOAD_WIDGETS_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+            fail("Timed out waiting for test")
+        }
+
+        // No exception
+    }
+
     private fun loadWidgets() {
         val latch = CountDownLatch(1)
         Executors.MODEL_EXECUTOR.execute {
diff --git a/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt b/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
deleted file mode 100644
index 8204313..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
+++ /dev/null
@@ -1,116 +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.launcher3.recyclerview
-
-import android.content.Context
-import android.view.View
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.util.Executors
-import com.android.launcher3.views.ActivityContext
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class AllAppsRecyclerViewPoolTest<T> where T : Context, T : ActivityContext {
-
-    private lateinit var underTest: AllAppsRecyclerViewPool<T>
-    private lateinit var adapter: RecyclerView.Adapter<*>
-
-    @Mock private lateinit var parent: ViewGroup
-    @Mock private lateinit var itemView: View
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        underTest = spy(AllAppsRecyclerViewPool())
-        adapter =
-            object : RecyclerView.Adapter<ViewHolder>() {
-                override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
-                    object : ViewHolder(itemView) {}
-
-                override fun getItemCount() = 0
-
-                override fun onBindViewHolder(holder: ViewHolder, position: Int) {}
-            }
-        underTest.setMaxRecycledViews(VIEW_TYPE, 20)
-    }
-
-    @Test
-    fun preinflate_success() {
-        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
-
-        awaitTasksCompleted()
-        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(10)
-    }
-
-    @Test
-    fun preinflate_not_triggered() {
-        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 0 }
-
-        awaitTasksCompleted()
-        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
-    }
-
-    @Test
-    fun preinflate_cancel_before_runOnMainThread() {
-        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
-        assertThat(underTest.mCancellableTask!!.canceled).isFalse()
-
-        underTest.clear()
-
-        awaitTasksCompleted()
-        verify(underTest, never()).putRecycledView(any(ViewHolder::class.java))
-        assertThat(underTest.mCancellableTask!!.canceled).isTrue()
-        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
-    }
-
-    @Test
-    fun preinflate_cancel_after_run() {
-        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
-        assertThat(underTest.mCancellableTask!!.canceled).isFalse()
-        awaitTasksCompleted()
-
-        underTest.clear()
-
-        verify(underTest, times(10)).putRecycledView(any(ViewHolder::class.java))
-        assertThat(underTest.mCancellableTask!!.canceled).isTrue()
-        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
-    }
-
-    private fun awaitTasksCompleted() {
-        Executors.VIEW_PREINFLATION_EXECUTOR.submit<Any> { null }.get()
-        Executors.MAIN_EXECUTOR.submit<Any> { null }.get()
-    }
-
-    companion object {
-        private const val VIEW_TYPE: Int = 4
-    }
-}
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index a1f2d50..aa7f388 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -26,7 +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_NEW_ARCHIVING_ICON;
+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,13 +416,14 @@
         assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(false);
     }
 
-    @EnableFlags(FLAG_ENABLE_NEW_ARCHIVING_ICON)
+    @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
     @Test
     public void applyIconAndLabel_setsImageSpan_whenInactiveArchivedApp() {
         // Given
         BubbleTextView spyTextView = spy(mBubbleTextView);
         mGmailAppInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
         BubbleTextView expectedTextView = new BubbleTextView(mContext);
+        mContext.getResources().getConfiguration().fontWeightAdjustment = 0;
         int expectedDrawableId = mContext.getResources().getIdentifier(
                 "cloud_download_24px", /* name */
                 "drawable", /* defType */
@@ -451,7 +452,7 @@
         assertThat(actualSpan.getVerticalAlignment()).isEqualTo(ALIGN_CENTER);
     }
 
-    @EnableFlags(FLAG_ENABLE_NEW_ARCHIVING_ICON)
+    @EnableFlags(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/TestDispatcherProvider.kt b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
new file mode 100644
index 0000000..39e1ec5
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.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.util
+
+import com.android.launcher3.util.coroutines.DispatcherProvider
+import kotlinx.coroutines.CoroutineDispatcher
+
+class TestDispatcherProvider(testDispatcher: CoroutineDispatcher) : DispatcherProvider {
+    override val default: CoroutineDispatcher = testDispatcher
+    override val io: CoroutineDispatcher = testDispatcher
+    override val main: CoroutineDispatcher = testDispatcher
+    override val unconfined: CoroutineDispatcher = testDispatcher
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt
new file mode 100644
index 0000000..79b493a
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.widget
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
+import java.util.function.IntConsumer
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertSame
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LauncherAppWidgetHostTest {
+
+    @Mock private lateinit var onAppWidgetRemovedCallback: IntConsumer
+
+    private val context = ActivityContextWrapper(getInstrumentation().targetContext)
+    private lateinit var underTest: LauncherAppWidgetHost
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest = LauncherAppWidgetHost(context, onAppWidgetRemovedCallback, emptyList())
+    }
+
+    @Test
+    fun `Host set view to recycle`() {
+        val mockRecycleView = mock(ListenableHostView::class.java)
+
+        assertNull(underTest.viewToRecycle)
+        underTest.recycleViewForNextCreation(mockRecycleView)
+
+        assertSame(mockRecycleView, underTest.viewToRecycle)
+    }
+
+    @Test
+    fun `Host create view`() {
+        val mockRecycleView = mock(ListenableHostView::class.java)
+
+        var resultView = underTest.onCreateView(context, WIDGET_ID, null)
+
+        assertNotSame(mockRecycleView, resultView)
+
+        underTest.recycleViewForNextCreation(mockRecycleView)
+        resultView = underTest.onCreateView(context, WIDGET_ID, null)
+
+        assertSame(mockRecycleView, resultView)
+    }
+
+    @Test
+    fun `Runnable called when app widget removed`() {
+        underTest.onAppWidgetRemoved(WIDGET_ID)
+
+        Executors.MODEL_EXECUTOR.submit {}.get()
+        getInstrumentation().waitForIdleSync()
+
+        verify(onAppWidgetRemovedCallback).accept(WIDGET_ID)
+    }
+
+    companion object {
+        const val WIDGET_ID = 10001
+    }
+}
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 5516f45..7c9f99a 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -25,16 +25,23 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
 import com.android.launcher3.LauncherPrefs.Companion.get
+import com.android.launcher3.graphics.PreloadIconDrawable
 import com.android.launcher3.icons.BaseIconFactory
 import com.android.launcher3.icons.FastBitmapDrawable
 import com.android.launcher3.icons.UserBadgeDrawable
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED
+import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE
+import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
 import com.android.launcher3.util.FlagOp
 import com.android.launcher3.util.LauncherLayoutBuilder
 import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.TestUtil
 import com.android.launcher3.util.UserIconInfo
+import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -219,6 +226,39 @@
         )
     }
 
+    @Test
+    fun `Inactive archived app previews are not drawn as preload icon`() {
+        // Given
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+        val archivedApp =
+            WorkspaceItemInfo().apply {
+                runtimeStatusFlags = runtimeStatusFlags or FLAG_ARCHIVED
+                runtimeStatusFlags = runtimeStatusFlags and FLAG_INSTALL_SESSION_ACTIVE.inv()
+            }
+        // When
+        previewItemManager.setDrawable(drawingParams, archivedApp)
+        // Then
+        assertThat(drawingParams.drawable).isNotInstanceOf(PreloadIconDrawable::class.java)
+    }
+
+    @Test
+    fun `Actively installing archived app previews are drawn as preload icon`() {
+        // Given
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+        val archivedApp =
+            WorkspaceItemInfo().apply {
+                runtimeStatusFlags = runtimeStatusFlags or FLAG_ARCHIVED
+                runtimeStatusFlags = runtimeStatusFlags or FLAG_INSTALL_SESSION_ACTIVE
+            }
+        // When
+        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) {
+            // Run on main thread because preload drawable triggers animator
+            previewItemManager.setDrawable(drawingParams, archivedApp)
+        }
+        // Then
+        assertThat(drawingParams.drawable).isInstanceOf(PreloadIconDrawable::class.java)
+    }
+
     private fun profileFlagOp(type: Int) =
         UserIconInfo(Process.myUserHandle(), type).applyBitmapInfoFlags(FlagOp.NO_OP)
 }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index c926ba9..749a75a 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
 import static com.android.launcher3.testing.shared.TestProtocol.WIDGET_CONFIG_NULL_EXTRA_INTENT;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -44,6 +43,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.rule.LimitDevicesRule;
 import android.system.OsConstants;
 import android.util.Log;
 
@@ -64,7 +64,6 @@
 import com.android.launcher3.tapl.TestHelpers;
 import com.android.launcher3.testcomponent.TestCommandReceiver;
 import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
@@ -224,6 +223,9 @@
     @Rule
     public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
 
+    @Rule
+    public LimitDevicesRule mlimitDevicesRule = new LimitDevicesRule();
+
     public static void initialize(AbstractLauncherUiTest test) throws Exception {
         test.reinitializeLauncherData();
         test.mDevice.pressHome();
@@ -237,16 +239,12 @@
     }
 
     protected void clearPackageData(String pkg) throws IOException, InterruptedException {
-        final CountDownLatch count = new CountDownLatch(2);
-        final SimpleBroadcastReceiver broadcastReceiver =
-                new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> count.countDown());
-        // We OK to make binder calls on main thread in test.
-        broadcastReceiver.registerPkgActions(mTargetContext, pkg,
-                Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED);
-
-        mDevice.executeShellCommand("pm clear " + pkg);
-        assertTrue(pkg + " didn't restart", count.await(20, TimeUnit.SECONDS));
-        mTargetContext.unregisterReceiver(broadcastReceiver);
+        assertTrue("pm clear command failed",
+                mDevice.executeShellCommand("pm clear " + pkg)
+                .contains("Success"));
+        assertTrue("pm wait-for-handler command failed",
+                mDevice.executeShellCommand("pm wait-for-handler")
+                .contains("Success"));
     }
 
     protected TestRule getRulesInsideActivityMonitor() {
diff --git a/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt b/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt
new file mode 100644
index 0000000..1cee71c
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.ui
+
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.views.DoubleShadowIconDrawable
+import com.android.launcher3.views.ShadowInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DoubleShadowIconDrawableTest {
+
+    @Test
+    fun `DoubleShadowIconDrawable is setup correctly from given ShadowInfo`() {
+        // Given
+        val shadowInfo: ShadowInfo = mock()
+        val originalDrawable: Drawable = mock()
+        val iconSize = 2
+        val iconInsetSize = 1
+        // When
+        val drawableUnderTest =
+            DoubleShadowIconDrawable(shadowInfo, originalDrawable, iconSize, iconInsetSize)
+        // Then
+        assertThat(drawableUnderTest.intrinsicHeight).isEqualTo(iconSize)
+        assertThat(drawableUnderTest.intrinsicWidth).isEqualTo(iconSize)
+    }
+
+    @Test
+    fun `createShadowRenderNode creates RenderNode for shadow effects`() {
+        // Given
+        val shadowInfo =
+            ShadowInfo(
+                ambientShadowBlur = 1f,
+                ambientShadowColor = 2,
+                keyShadowBlur = 3f,
+                keyShadowOffsetX = 4f,
+                keyShadowOffsetY = 5f,
+                keyShadowColor = 6
+            )
+        val originalDrawable: Drawable = mock()
+        val iconSize = 2
+        val iconInsetSize = 1
+        // When
+        val shadowDrawableUnderTest =
+            spy(DoubleShadowIconDrawable(shadowInfo, originalDrawable, iconSize, iconInsetSize))
+        shadowDrawableUnderTest.createShadowRenderNode()
+        // Then
+        verify(shadowDrawableUnderTest)
+            .createShadowRenderEffect(
+                shadowInfo.ambientShadowBlur,
+                0f,
+                0f,
+                Color.alpha(shadowInfo.ambientShadowColor).toFloat()
+            )
+        verify(shadowDrawableUnderTest)
+            .createShadowRenderEffect(
+                shadowInfo.keyShadowBlur,
+                shadowInfo.keyShadowOffsetX,
+                shadowInfo.keyShadowOffsetY,
+                Color.alpha(shadowInfo.keyShadowColor).toFloat()
+            )
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt b/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt
new file mode 100644
index 0000000..ef4dc1a
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.ui
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.util.AttributeSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.R
+import com.android.launcher3.views.ShadowInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShadowInfoTest {
+
+    @Test
+    fun `ShadowInfo is created correctly from context`() {
+        // Given
+        val mockContext: Context = mock()
+        val mockAttrs: AttributeSet = mock()
+        val styledAttrs: TypedArray = mock()
+        val expectedShadowInfo =
+            ShadowInfo(
+                ambientShadowBlur = 1f,
+                ambientShadowColor = 2,
+                keyShadowBlur = 3f,
+                keyShadowOffsetX = 4f,
+                keyShadowOffsetY = 5f,
+                keyShadowColor = 6
+            )
+        doReturn(styledAttrs)
+            .whenever(mockContext)
+            .obtainStyledAttributes(mockAttrs, R.styleable.ShadowInfo, 0, 0)
+        doReturn(1)
+            .whenever(styledAttrs)
+            .getDimensionPixelSize(R.styleable.ShadowInfo_ambientShadowBlur, 0)
+        doReturn(2).whenever(styledAttrs).getColor(R.styleable.ShadowInfo_ambientShadowColor, 0)
+        doReturn(3)
+            .whenever(styledAttrs)
+            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0)
+        doReturn(4)
+            .whenever(styledAttrs)
+            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0)
+        doReturn(5)
+            .whenever(styledAttrs)
+            .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0)
+        doReturn(6).whenever(styledAttrs).getColor(R.styleable.ShadowInfo_keyShadowColor, 0)
+        // When
+        val actualShadowInfo = ShadowInfo.fromContext(mockContext, mockAttrs, 0)
+        // Then
+        assertThat(actualShadowInfo.ambientShadowBlur).isEqualTo(1)
+        assertThat(actualShadowInfo.ambientShadowColor).isEqualTo(2)
+        assertThat(actualShadowInfo.keyShadowBlur).isEqualTo(3)
+        assertThat(actualShadowInfo.keyShadowOffsetX).isEqualTo(4)
+        assertThat(actualShadowInfo.keyShadowOffsetY).isEqualTo(5)
+        assertThat(actualShadowInfo.keyShadowColor).isEqualTo(6)
+        assertThat(actualShadowInfo).isEqualTo(expectedShadowInfo)
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 988aa94..b7ebfcd 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.tapl;
 
-import static com.android.launcher3.tapl.BaseOverview.TASK_RES_ID;
+import static com.android.launcher3.tapl.BaseOverview.TASK_SELECTOR;
 import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
 
@@ -117,10 +117,10 @@
                         // non-tablet overview, snapshots can be on either side of the swiped
                         // task, but we still check that they become visible after swiping and
                         // pausing.
-                        mLauncher.waitForOverviewObject(TASK_RES_ID);
+                        mLauncher.waitForObjectBySelector(TASK_SELECTOR);
                         if (mLauncher.isTablet()) {
                             List<UiObject2> tasks = mLauncher.getDevice().findObjects(
-                                    mLauncher.getOverviewObjectSelector(TASK_RES_ID));
+                                    TASK_SELECTOR);
                             final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
                             mLauncher.assertTrue(
                                     "All tasks not to the left of the swiped task",
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 567a8bd..e71b49f 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -19,7 +19,9 @@
 import static android.view.KeyEvent.KEYCODE_ESCAPE;
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
+import static com.android.launcher3.tapl.LauncherInstrumentation.log;
 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 android.graphics.Rect;
@@ -35,9 +37,11 @@
 
 import com.android.launcher3.testing.shared.TestProtocol;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -46,7 +50,9 @@
  */
 public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
     private static final String TAG = "BaseOverview";
-    protected static final String TASK_RES_ID = "task";
+    protected static final BySelector TASK_SELECTOR = By.res(Pattern.compile(
+            getOverviewPackageName()
+                    + ":id/(task_view_single|task_view_grouped|task_view_desktop)"));
     private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
             "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
     private static final Pattern EVENT_ENTER_DOWN = Pattern.compile(
@@ -56,10 +62,22 @@
 
     private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
 
+    private final @Nullable UiObject2 mLiveTileTask;
+
+
     BaseOverview(LauncherInstrumentation launcher) {
+        this(launcher, /*launchedFromApp=*/false);
+    }
+
+    BaseOverview(LauncherInstrumentation launcher, boolean launchedFromApp) {
         super(launcher);
         verifyActiveContainer();
         verifyActionsViewVisibility();
+        if (launchedFromApp) {
+            mLiveTileTask = getCurrentTaskUnchecked();
+        } else {
+            mLiveTileTask = null;
+        }
     }
 
     @Override
@@ -79,7 +97,7 @@
     private void flingForwardImpl() {
         try (LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to fling forward in overview")) {
-            LauncherInstrumentation.log("Overview.flingForward before fling");
+            log("Overview.flingForward before fling");
             final UiObject2 overview = verifyActiveContainer();
             final int leftMargin =
                     mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth();
@@ -105,7 +123,7 @@
     private void flingBackwardImpl() {
         try (LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to fling backward in overview")) {
-            LauncherInstrumentation.log("Overview.flingBackward before fling");
+            log("Overview.flingBackward before fling");
             final UiObject2 overview = verifyActiveContainer();
             final int rightMargin =
                     mLauncher.getTargetInsets().right + mLauncher.getEdgeSensitivityWidth();
@@ -276,37 +294,56 @@
      */
     @NonNull
     public OverviewTask getCurrentTask() {
+        UiObject2 currentTask = getCurrentTaskUnchecked();
+        mLauncher.assertNotNull("Unable to find a task", currentTask);
+        return new OverviewTask(mLauncher, currentTask, this);
+    }
+
+    @Nullable
+    private UiObject2 getCurrentTaskUnchecked() {
         final List<UiObject2> taskViews = getTasks();
-        mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+        if (taskViews.isEmpty()) {
+            return null;
+        }
 
         // The widest, and most top-right task should be the current task
-        UiObject2 currentTask = Collections.max(taskViews,
+        return Collections.max(taskViews,
                 Comparator.comparingInt((UiObject2 t) -> t.getVisibleBounds().width())
                         .thenComparingInt((UiObject2 t) -> t.getVisibleCenter().x)
                         .thenComparing(Comparator.comparing(
                                 (UiObject2 t) -> t.getVisibleCenter().y).reversed()));
-        return new OverviewTask(mLauncher, currentTask, this);
     }
 
-    /** Returns an overview task matching TestActivity {@param activityNumber}. */
+    /**
+     * Returns an overview task that contains the specified test activity in its thumbnails.
+     *
+     * @param activityIndex index of TestActivity to match against
+     */
     @NonNull
-    public OverviewTask getTestActivityTask(int activityNumber) {
+    public OverviewTask getTestActivityTask(int activityIndex) {
+        return getTestActivityTask(Collections.singleton(activityIndex));
+    }
+
+    /**
+     * Returns an overview task that contains all the specified test activities in its thumbnails.
+     *
+     * @param activityNumbers collection of indices of TestActivity to match against
+     */
+    @NonNull
+    public OverviewTask getTestActivityTask(Collection<Integer> activityNumbers) {
         final List<UiObject2> taskViews = getTasks();
         mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
 
-        final String activityName = "TestActivity" + activityNumber;
-        UiObject2 task = null;
-        for (UiObject2 taskView : taskViews) {
-            // TODO(b/239452415): Use equals instead of descEndsWith
-            if (taskView.getParent().hasObject(By.descEndsWith(activityName))) {
-                task = taskView;
-                break;
-            }
-        }
-        mLauncher.assertNotNull(
-                "Unable to find a task with " + activityName + " from the task list", task);
+        Optional<UiObject2> task = taskViews.stream().filter(
+                taskView -> activityNumbers.stream().allMatch(activityNumber ->
+                    // TODO(b/239452415): Use equals instead of descEndsWith
+                    taskView.hasObject(By.descEndsWith("TestActivity" + activityNumber))
+                )).findFirst();
 
-        return new OverviewTask(mLauncher, task, this);
+        mLauncher.assertTrue("Unable to find a task with test activities " + activityNumbers
+                + " from the task list", task.isPresent());
+
+        return new OverviewTask(mLauncher, task.get(), this);
     }
 
     /**
@@ -328,8 +365,7 @@
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get overview tasks")) {
             verifyActiveContainer();
-            return mLauncher.getDevice().findObjects(
-                    mLauncher.getOverviewObjectSelector(TASK_RES_ID));
+            return mLauncher.getDevice().findObjects(TASK_SELECTOR);
         }
     }
 
@@ -506,4 +542,10 @@
         }
         return null;
     }
+
+    protected boolean isLiveTile(UiObject2 task) {
+        // UiObject2.equals returns false even when mLiveTileTask and task have the same node, hence
+        // compare only hashCode as a workaround.
+        return mLiveTileTask != null && mLiveTileTask.hashCode() == task.hashCode();
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 200f2ff..b3ad930 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -33,6 +33,7 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
+import androidx.annotation.NonNull;
 import androidx.test.uiautomator.Condition;
 import androidx.test.uiautomator.UiDevice;
 
@@ -75,6 +76,20 @@
         return false;
     }
 
+    @NonNull
+    @Override
+    public BaseOverview switchToOverview() {
+        try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer(
+                     "want to switch from background to overview")) {
+            verifyActiveContainer();
+            goToOverviewUnchecked();
+            return mLauncher.is3PLauncher()
+                    ? new BaseOverview(mLauncher, /*launchedFromApp=*/true)
+                    : new Overview(mLauncher, /*launchedFromApp=*/true);
+        }
+    }
+
     /**
      * Returns the taskbar.
      *
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 75c1b24..a874062 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1585,7 +1585,7 @@
         return objects;
     }
 
-    private UiObject2 waitForObjectBySelector(BySelector selector) {
+    UiObject2 waitForObjectBySelector(BySelector selector) {
         Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
                 "LauncherInstrumentation.waitForObjectBySelector");
         final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 50c2136..deb27e4 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -22,9 +22,12 @@
  * Overview pane.
  */
 public class Overview extends BaseOverview {
-
     Overview(LauncherInstrumentation launcher) {
-        super(launcher);
+        this(launcher, /*launchedFromApp=*/false);
+    }
+
+    Overview(LauncherInstrumentation launcher, boolean launchedFromApp) {
+        super(launcher, launchedFromApp);
     }
 
     @Override
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 6f420af..7a8ab49 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -40,16 +40,23 @@
 public final class OverviewTask {
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
     static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync");
+    static final Pattern TASK_START_EVENT_DESKTOP = Pattern.compile("launchDesktopFromRecents");
+    static final Pattern TASK_START_EVENT_LIVE_TILE = Pattern.compile(
+            "composeRecentsLaunchAnimator");
     static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect");
     static final Pattern SPLIT_START_EVENT = Pattern.compile("launchSplitTasks");
     private final LauncherInstrumentation mLauncher;
+    @NonNull
     private final UiObject2 mTask;
+    private final TaskViewType mType;
     private final BaseOverview mOverview;
 
-    OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview) {
+    OverviewTask(LauncherInstrumentation launcher, @NonNull UiObject2 task, BaseOverview overview) {
         mLauncher = launcher;
+        mLauncher.assertNotNull("task must not be null", task);
         mTask = task;
         mOverview = overview;
+        mType = getType();
         verifyActiveContainer();
     }
 
@@ -220,7 +227,22 @@
                     return new LaunchedAppState(mLauncher);
                 }
             } else {
-                mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
+                final Pattern event;
+                if (mOverview.isLiveTile(mTask)) {
+                    event = TASK_START_EVENT_LIVE_TILE;
+                } else if (mType == TaskViewType.DESKTOP) {
+                    event = TASK_START_EVENT_DESKTOP;
+                } else {
+                    event = TASK_START_EVENT;
+                }
+                mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, event);
+
+                if (mType == TaskViewType.DESKTOP) {
+                    try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer(
+                            "launched desktop")) {
+                        mLauncher.waitForSystemUiObject("desktop_mode_caption");
+                    }
+                }
                 return new LaunchedAppState(mLauncher);
             }
         }
@@ -273,6 +295,17 @@
         return actual.contains(expected);
     }
 
+    private TaskViewType getType() {
+        String resourceName = mTask.getResourceName();
+        if (resourceName.endsWith("task_view_grouped")) {
+            return TaskViewType.GROUPED;
+        } else if (resourceName.endsWith("task_view_desktop")) {
+            return TaskViewType.DESKTOP;
+        } else {
+            return TaskViewType.SINGLE;
+        }
+    }
+
     /**
      * Enum used to specify  which task is retrieved when it is a split task.
      */
@@ -292,4 +325,10 @@
             this.iconAppRes = iconAppRes;
         }
     }
+
+    private enum TaskViewType {
+        SINGLE,
+        GROUPED,
+        DESKTOP
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 902ad5b..90d32f3 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -97,6 +97,29 @@
         }
     }
 
+    /**
+     * Taps the Desktop item from the overview task menu and returns the LaunchedAppState
+     * representing the Desktop.
+     */
+    @NonNull
+    public LaunchedAppState tapDesktopMenuItem() {
+        try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer(
+                     "before tapping the desktop menu item")) {
+            mLauncher.executeAndWaitForLauncherStop(
+                    () -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.text("Desktop"))),
+                    "tapped desktop menu item");
+
+            try (LauncherInstrumentation.Closable ignored2 = mLauncher.addContextLayer(
+                    "tapped desktop menu item")) {
+                mLauncher.waitUntilSystemLauncherObjectGone("overview_panel");
+                mLauncher.waitForSystemUiObject("desktop_mode_caption");
+                return new LaunchedAppState(mLauncher);
+            }
+        }
+    }
+
     /** Returns true if an item matching the given string is present in the menu. */
     public boolean hasMenuItem(String expectedMenuItemText) {
         UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText));
@@ -104,14 +127,6 @@
     }
 
     /**
-     * Returns the menu item specified by name if present.
-     */
-    public OverviewTaskMenuItem getMenuItemByName(String menuItemName) {
-        return new OverviewTaskMenuItem(mLauncher,
-                mLauncher.waitForObjectInContainer(mMenu, By.text(menuItemName)));
-    }
-
-    /**
      * Taps outside task menu to dismiss it.
      */
     public void touchOutsideTaskMenuToDismiss() {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java
deleted file mode 100644
index e3035bf..0000000
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.tapl;
-
-import android.graphics.Rect;
-
-import androidx.test.uiautomator.UiObject2;
-
-/** Represents an item in the overview task menu. */
-public class OverviewTaskMenuItem {
-
-    private final LauncherInstrumentation mLauncher;
-    private final UiObject2 mMenuItem;
-
-    OverviewTaskMenuItem(LauncherInstrumentation launcher, UiObject2 menuItem) {
-        mLauncher = launcher;
-        mMenuItem = menuItem;
-    }
-
-    /**
-     * Returns this menu item's visible bounds.
-     */
-    public Rect getVisibleBounds() {
-        return mMenuItem.getVisibleBounds();
-    }
-}