Merge "Update alpha animation for All Apps / Divider icon." into main
diff --git a/Android.bp b/Android.bp
index eed67f5..13a926b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -141,6 +141,7 @@
     static_libs: [
         "LauncherPluginLib",
         "launcher_quickstep_log_protos_lite",
+        "android.os.flags-aconfig-java",
         "androidx-constraintlayout_constraintlayout",
         "androidx.recyclerview_recyclerview",
         "androidx.dynamicanimation_dynamicanimation",
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index a31ee80..edbea88 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -52,18 +52,18 @@
     name in the permissions. eq com.mypackage.permission.READ_SETTINGS
     -->
     <permission
-        android:name="${packageName}.permission.READ_SETTINGS"
+        android:name="${applicationId}.permission.READ_SETTINGS"
         android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_read_settings"
         android:description="@string/permdesc_read_settings"/>
     <permission
-        android:name="${packageName}.permission.WRITE_SETTINGS"
+        android:name="${applicationId}.permission.WRITE_SETTINGS"
         android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_write_settings"
         android:description="@string/permdesc_write_settings"/>
 
-    <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
-    <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="${applicationId}.permission.READ_SETTINGS" />
+    <uses-permission android:name="${applicationId}.permission.WRITE_SETTINGS" />
 
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -126,10 +126,10 @@
         -->
         <provider
             android:name="com.android.launcher3.LauncherProvider"
-            android:authorities="${packageName}.settings"
+            android:authorities="${applicationId}.settings"
             android:exported="true"
-            android:writePermission="${packageName}.permission.WRITE_SETTINGS"
-            android:readPermission="${packageName}.permission.READ_SETTINGS" />
+            android:writePermission="${applicationId}.permission.WRITE_SETTINGS"
+            android:readPermission="${applicationId}.permission.READ_SETTINGS" />
 
         <!--
         The content provider for exposing various launcher grid options.
@@ -137,7 +137,7 @@
         -->
         <provider
             android:name="com.android.launcher3.graphics.GridCustomizationsProvider"
-            android:authorities="${packageName}.grid_control"
+            android:authorities="${applicationId}.grid_control"
             android:exported="true" />
 
         <!--
@@ -157,7 +157,7 @@
 
         <provider
             android:name="com.android.launcher3.testing.TestInformationProvider"
-            android:authorities="${packageName}.TestInfo"
+            android:authorities="${applicationId}.TestInfo"
             android:readPermission="android.permission.WRITE_SECURE_SETTINGS"
             android:writePermission="android.permission.WRITE_SECURE_SETTINGS"
             android:exported="true"
diff --git a/OWNERS b/OWNERS
index 654493f..e715b8b 100644
--- a/OWNERS
+++ b/OWNERS
@@ -28,6 +28,7 @@
 tracyzhou@google.com
 peanutbutter@google.com
 jeremysim@google.com
+atsjenk@google.com
 
 # Overview eng team
 alexchau@google.com
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 8274bd6..dd78ca4 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -229,3 +229,51 @@
     description: "Enables an add button in the widget picker"
     bug: "323886237"
 }
+
+flag {
+    name: "enable_refactor_task_thumbnail"
+    namespace: "launcher"
+    description: "Enables rewritten version of TaskThumbnailViews in Overview"
+    bug: "331753115"
+}
+
+flag {
+  name: "enable_handle_delayed_gesture_callbacks"
+  namespace: "launcher"
+  description: "Enables additional handling for delayed mid-gesture callbacks"
+  bug: "285636175"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+    name: "enable_fallback_overview_in_window"
+    namespace: "launcher"
+    description: "Enables fallback recents opening inside of a window instead of an activity."
+    bug: "292269949"
+}
+
+flag {
+    name: "enable_smartspace_as_a_widget"
+    namespace: "launcher"
+    description: "Enables smartspace as a widget"
+    bug: "300140279"
+}
+
+flag {
+    name: "enable_smartspace_removal_toggle"
+    namespace: "launcher"
+    description: "Enables smartspace removal toggle"
+    bug: "303471576"
+}
+
+flag {
+  name: "enable_additional_home_animations"
+  namespace: "launcher"
+  description: "Enables custom home animations for non-running tasks"
+  bug: "237638627"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index df09124..b1a6202 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -121,6 +121,17 @@
             android:layout_weight="1"
             android:visibility="gone" />
 
+    </LinearLayout>
+
+    <!-- Unused. Included only for compatibility with parent class. -->
+    <LinearLayout
+        android:id="@+id/group_action_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/overview_actions_height"
+        android:layout_gravity="top|center_horizontal"
+        android:orientation="horizontal"
+        android:visibility="gone">
+
         <Button
             android:id="@+id/action_save_app_pair"
             style="@style/GoOverviewActionButton"
@@ -128,8 +139,8 @@
             android:layout_height="wrap_content"
             android:drawableStart="@drawable/ic_save_app_pair_up_down"
             android:text="@string/action_save_app_pair"
-            android:theme="@style/ThemeControlHighlightWorkspaceColor"
-            android:visibility="gone" />
+            android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
     </LinearLayout>
 
 </com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/go/quickstep/res/values-ne/strings.xml b/go/quickstep/res/values-ne/strings.xml
index cee6603..e66f063 100644
--- a/go/quickstep/res/values-ne/strings.xml
+++ b/go/quickstep/res/values-ne/strings.xml
@@ -8,7 +8,7 @@
     <string name="dialog_acknowledge" msgid="2804025517675853172">"बुझेँ"</string>
     <string name="dialog_cancel" msgid="6464336969134856366">"रद्द गर्नुहोस्"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"सेटिङ"</string>
-    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"स्क्रिनमा देखिने पाठ अनुवाद गर्नुहोस् वा पढेर सुनाइयोस्"</string>
+    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"स्क्रिनमा देखिने पाठ अनुवाद गर्नुहोस् वा पढेर सुनाउनुहोस्"</string>
     <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"तपाईंको स्क्रिनमा देखिने पाठ, वेब ठेगाना र स्क्रिनसटलगायतका जानकारी Google सँग सेयर गर्न सकिन्छ।\n\nकुन कुन जानकारी सेयर गर्न दिने भन्ने सेटिङ बदल्न "<b>"सेटिङ &gt; एप &gt; डिफल्ट एप &gt; डिजिटल सहायक एप"</b>" मा जानुहोस्।"</string>
     <string name="assistant_not_selected_title" msgid="5017072974603345228">"तपाईं यो सुविधा चलाउन चाहनुहुन्छ भने कुनै सहायक छनौट गर्नुहोस्"</string>
     <string name="assistant_not_selected_text" msgid="3244613673884359276">"तपाईं आफ्नो स्क्रिनमा देखिने पाठ सुन्न वा अनुवाद गर्न चाहनुहुन्छ भने सेटिङमा गई कुनै डिजिटल सहायक एप छनौट गर्नुहोस्"</string>
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
index 0d0f700..556d29c 100644
--- a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.launcher3.model.AppShareabilityDatabase.ShareabilityDao;
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
@@ -47,7 +48,7 @@
  * Each app's status is retrieved from the Play Store's API. Statuses are cached in order
  * to limit extraneous calls to that API (which can be time-consuming).
  */
-public class AppShareabilityManager {
+public class AppShareabilityManager implements SafeCloseable {
     @Retention(SOURCE)
     @IntDef({
         ShareabilityStatus.UNKNOWN,
@@ -194,6 +195,11 @@
         }
     }
 
+    @Override
+    public void close() {
+        mDatabase.close();
+    }
+
     /**
      * Provides a testable instance of this class
      * This instance allows database queries on the main thread
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 253147d..0eb8775 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -56,7 +56,7 @@
 import com.android.quickstep.util.AssistContentRequester;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.GoOverviewActionsView;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -101,7 +101,7 @@
     /**
      * Create a new overlay instance for the given View
      */
-    public TaskOverlayGo createOverlay(TaskThumbnailView thumbnailView) {
+    public TaskOverlayGo createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
         return new TaskOverlayGo(thumbnailView, mContentRequester);
     }
 
@@ -120,7 +120,7 @@
         private OverlayDialogGo mDialog;
         private ArrowTipView mArrowTipView;
 
-        private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
+        private TaskOverlayGo(TaskThumbnailViewDeprecated taskThumbnailView,
                 AssistContentRequester assistContentRequester) {
             super(taskThumbnailView);
             mFactoryContentRequester = assistContentRequester;
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index e75812a..bf198b6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -50,7 +50,7 @@
     <uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
 
     <!-- Permission required to start a WidgetPickerActivity. -->
-    <permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
+    <permission android:name="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY"
         android:protectionLevel="signature|privileged" />
 
     <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -83,11 +83,12 @@
              android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
              android:resizeableActivity="true"
              android:resumeWhilePausing="true"
+             android:enableOnBackInvokedCallback="false"
              android:taskAffinity=""/>
 
         <!-- Content provider to settings search. The autority should be same as the packageName -->
         <provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
-             android:authorities="${packageName}"
+             android:authorities="${applicationId}"
              android:grantUriPermissions="true"
              android:multiprocess="true"
              android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -99,7 +100,7 @@
 
         <!-- FileProvider used for sharing images. -->
         <provider android:name="androidx.core.content.FileProvider"
-             android:authorities="${packageName}.overview.fileprovider"
+             android:authorities="${applicationId}.overview.fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
             <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
diff --git a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
new file mode 100644
index 0000000..d722dd7
--- /dev/null
+++ b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
@@ -0,0 +1,27 @@
+<?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.
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:inset="@dimen/bubble_expanded_view_drop_target_padding">
+    <shape
+        android:shape="rectangle">
+        <corners android:radius="@dimen/bubble_expanded_view_drop_target_corner_radius" />
+        <solid android:color="@color/bubblebar_drop_target_bg_color" />
+        <stroke
+            android:width="1dp"
+            android:color="?androidprv:attr/materialColorPrimaryContainer" />
+    </shape>
+</inset>
diff --git a/quickstep/res/layout/bubble_expanded_view_drop_target.xml b/quickstep/res/layout/bubble_expanded_view_drop_target.xml
new file mode 100644
index 0000000..3bd5d31
--- /dev/null
+++ b/quickstep/res/layout/bubble_expanded_view_drop_target.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- TODO(b/330585402): replace 600dp height with calculated value -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/bubble_expanded_view_drop_target_default_width"
+    android:layout_height="@dimen/bubble_expanded_view_drop_target_default_height"
+    android:layout_margin="@dimen/bubble_expanded_view_drop_target_margin"
+    android:background="@drawable/bg_bubble_expanded_view_drop_target"
+    android:elevation="@dimen/bubblebar_elevation" />
\ No newline at end of file
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
similarity index 97%
rename from quickstep/res/layout/keyboard_quick_switch_overview.xml
rename to quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
index 30ca32d..e48794e 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
@@ -40,7 +40,6 @@
             android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
             android:layout_marginBottom="8dp"
-            android:src="@drawable/view_carousel"
             android:tint="?androidprv:attr/materialColorOnSurface"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index d086da4..7aaf744 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -45,14 +45,24 @@
             android:theme="@style/ThemeControlHighlightWorkspaceColor"
             android:visibility="gone" />
 
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/group_action_buttons"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/overview_actions_height"
+        android:layout_gravity="bottom|center_horizontal"
+        android:orientation="horizontal"
+        android:visibility="gone">
+
         <Button
             android:id="@+id/action_save_app_pair"
             style="@style/OverviewActionButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/action_save_app_pair"
-            android:theme="@style/ThemeControlHighlightWorkspaceColor"
-            android:visibility="gone" />
+            android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
     </LinearLayout>
 
 </com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index a1bcad0..b004dfd 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -134,11 +134,12 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
+        android:layout_above="@id/gesture_tutorial_fragment_action_button"
         android:layout_centerHorizontal="true"
         android:background="@android:color/transparent"
-        android:paddingEnd="24dp"
-        android:paddingStart="24dp"
-        android:paddingTop="24dp">
+        android:paddingTop="24dp"
+        android:paddingHorizontal="24dp"
+        android:layout_marginBottom="16dp">
 
         <TextView
             android:id="@+id/gesture_tutorial_fragment_feedback_title"
@@ -169,7 +170,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
 
-            app:layout_constraintBottom_toBottomOf="@id/gesture_tutorial_fragment_action_button"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
@@ -193,7 +194,7 @@
             android:id="@+id/checkmark_animation"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="44dp"
+            android:layout_marginBottom="28dp"
             android:gravity="center"
             android:scaleType="centerCrop"
             app:lottie_loop="false"
@@ -204,19 +205,6 @@
             app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle"
             app:layout_constraintBottom_toBottomOf="parent" />
 
-        <Button
-            android:id="@+id/gesture_tutorial_fragment_action_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="@drawable/gesture_tutorial_action_button_background"
-            android:stateListAnimator="@null"
-            android:text="@string/gesture_tutorial_action_button_label"
-            android:visibility="invisible"
-            android:layout_marginBottom="60dp"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/checkmark_animation" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
@@ -228,4 +216,18 @@
         android:src="@drawable/gesture_tutorial_finger_dot"
         android:visibility="gone" />
 
+    <Button
+        android:id="@+id/gesture_tutorial_fragment_action_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/gesture_tutorial_done_button_end_margin"
+        android:layout_marginBottom="@dimen/gesture_tutorial_done_button_bottom_margin"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:background="@drawable/gesture_tutorial_action_button_background"
+        android:stateListAnimator="@null"
+        android:text="@string/gesture_tutorial_action_button_label"
+        android:visibility="invisible"
+         />
+
 </com.android.quickstep.interaction.RootSandboxLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 9d599c9..cc3b30e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,10 +28,7 @@
     launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
     launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
 
-    <com.android.quickstep.views.TaskThumbnailView
-        android:id="@+id/snapshot"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+    <include layout="@layout/task_thumbnail" />
 
     <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
          separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 3cafcfd..89e9b3d 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -42,10 +42,7 @@
          views that do not inherint from TaskView only or create a generic TaskView that have
          N number of tasks.
      -->
-    <com.android.quickstep.views.TaskThumbnailView
-        android:id="@+id/snapshot"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+    <include layout="@layout/task_thumbnail"
         android:visibility="gone" />
 
     <ViewStub
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index e91e773..87a0f70 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,15 +33,10 @@
     launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
     launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
 
-    <com.android.quickstep.views.TaskThumbnailView
-        android:id="@+id/snapshot"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+    <include layout="@layout/task_thumbnail"/>
 
-    <com.android.quickstep.views.TaskThumbnailView
-        android:id="@+id/bottomright_snapshot"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+    <include layout="@layout/task_thumbnail"
+        android:id="@+id/bottomright_snapshot" />
 
     <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
          separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml
index c9108a5..88e5cf7 100644
--- a/quickstep/res/layout/task_menu_with_arrow.xml
+++ b/quickstep/res/layout/task_menu_with_arrow.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:minWidth="@dimen/task_menu_width_grid"
     android:animateLayoutChanges="true"
     android:background="@drawable/task_menu_bg"
     android:orientation="vertical"
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
new file mode 100644
index 0000000..f1a3d62
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail.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.
+-->
+<com.android.quickstep.views.TaskThumbnailViewDeprecated
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/snapshot"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu_circle_to_search.xml b/quickstep/res/layout/taskbar_edu_search.xml
similarity index 79%
rename from quickstep/res/layout/taskbar_edu_circle_to_search.xml
rename to quickstep/res/layout/taskbar_edu_search.xml
index 6c95f25..ca84f35 100644
--- a/quickstep/res/layout/taskbar_edu_circle_to_search.xml
+++ b/quickstep/res/layout/taskbar_edu_search.xml
@@ -23,35 +23,35 @@
         style="@style/TextAppearance.TaskbarEduTooltip.Title"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:text="@string/taskbar_edu_circle_to_search_title"
+        android:text="@string/taskbar_search_edu_title"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@+id/circle_to_search_animation" />
+        app:layout_constraintBottom_toTopOf="@+id/search_edu_animation" />
 
     <com.airbnb.lottie.LottieAnimationView
-        android:id="@+id/circle_to_search_animation"
+        android:id="@+id/search_edu_animation"
         android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
         android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
         android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
-        app:layout_constraintBottom_toTopOf="@id/circle_to_search_text"
+        app:layout_constraintBottom_toTopOf="@id/search_edu_text"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/title"
-        app:lottie_rawRes="@raw/taskbar_edu_circle_to_search"
+        app:lottie_rawRes="@raw/taskbar_edu_search"
         app:lottie_autoPlay="true"
         app:lottie_loop="true" />
 
     <TextView
-        android:id="@+id/circle_to_search_text"
+        android:id="@+id/search_edu_text"
         style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="center"
-        android:textSize="@dimen/taskbar_edu_circle_to_search_subtitle_text_size"
+        android:textSize="@dimen/taskbar_edu_search_subtitle_text_size"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/circle_to_search_animation"
+        app:layout_constraintTop_toBottomOf="@id/search_edu_animation"
         app:layout_constraintBottom_toBottomOf="parent" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 3c6878a..7c55bf8 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -44,7 +44,7 @@
         android:layout_height="@dimen/bubblebar_size_with_pointer"
         android:layout_gravity="bottom|end"
         android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
-        android:paddingTop="@dimen/bubblebar_pointer_size"
+        android:paddingTop="@dimen/bubblebar_pointer_visible_size"
         android:paddingEnd="@dimen/taskbar_icon_spacing"
         android:paddingStart="@dimen/taskbar_icon_spacing"
         android:visibility="gone"
diff --git a/quickstep/res/raw/taskbar_edu_circle_to_search.json b/quickstep/res/raw/taskbar_edu_search.json
similarity index 100%
rename from quickstep/res/raw/taskbar_edu_circle_to_search.json
rename to quickstep/res/raw/taskbar_edu_search.json
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index e1f52e7..39cca0c 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Doen meer met die Taakbalk"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Wys altyd die Taakbalk"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Raak en hou die verdeler in om altyd die Taakbalk onderaan jou skerm te wys"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Raak en hou die aksiesleutel om te soek wat op jou skerm is"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Hierdie produk gebruik die deel van jou skerm wat gekies is om te soek. Google se <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privaatheidsbeleid<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> en <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>diensbepalings<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> geld."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Raak en hou die handelingsleutel om te soek wat op jou skerm is"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Hierdie produk gebruik die gekose deel van jou skerm om te soek. Google se <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privaatheidsbeleid<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> en <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>diensbepalings<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> geld."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Maak toe"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Tuis"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Voeg nou app by werkskerm"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Kanselleer"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 959d06c..948a86d 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"በተግባር አሞሌው ተጨማሪ ነገር ያድርጉ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"የተግባር አሞሌውን ሁልጊዜ አሳይ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"በማያ ገጽዎ ግርጌ ላይ ያለውን የተግባር አሞሌ ሁልጊዜ ለማሳየት፣ መክፈያን ይንኩ እና ይያዙ"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"በማያ ገጽዎ ላይ ያለውን ነገር ለመፈለግ የተግባር ቁልፉን ነክተው ይያዙ"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ይህ ምርት የተመረጠውን የማያ ገጽዎን ክፍል ለመፈለግ ይጠቀማል። የGoogle <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>የግላዊነት መመሪያ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> እና <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>የአገልግሎት ውል<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ተፈጻሚ ናቸው።"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"በማያ ገጽዎ ላይ ያለውን ነገር ለመፈለግ የተግባር ቁልፉን ነክተው ይያዙ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ይህ ምርት የተመረጠውን የማያ ገጽዎን ክፍል ለመፈለግ ይጠቀማል። የGoogle <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>የግላዊነት መመሪያ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> እና <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>የአገልግሎት ውል<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ተፈጻሚ ናቸው።"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ተጠናቅቋል"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"መነሻ"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"መተግበሪያን ወደ ዴስክቶፕ በማከል ላይ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ይቅር"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 2eaea0c..31f8922 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -89,9 +88,9 @@
     <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="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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"إنجاز المزيد باستخدام شريط التطبيقات"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"عرض \"شريط التطبيقات\" دائمًا"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"انقر مع الاستمرار على أداة تقسيم الشاشة لعرض \"شريط التطبيقات\" دائمًا في أسفل الشاشة."</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"انقر مع الاستمرار على مفتاح الإجراء للبحث عن المحتوى الذي يظهر على شاشتك"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏يستخدم هذا المنتج الجزء المحدّد من الشاشة للبحث. تسري <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>سياسة خصوصية<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> Google و<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>بنود خدمتها<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"انقر مع الاستمرار على مفتاح الإجراء للبحث عن المحتوى الذي يظهر على شاشتك"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"‏يستخدم هذا المنتج الجزء المحدّد من الشاشة للبحث. تسري <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>سياسة الخصوصية<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> و<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>بنود الخدمة<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> في Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تم"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"الرئيسية"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"إضافة تطبيق إلى سطح المكتب"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"إلغاء"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 72482ff..009993d 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"টাস্কবাৰৰ জৰিয়তে অধিক কাৰ্য সম্পাদন কৰক"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবাৰডাল সদায় দেখুৱাওক"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"আপোনাৰ স্ক্ৰীনৰ তলত সদায় টাস্কবাৰডাল দেখুৱাবলৈ বিভাজকডাল স্পৰ্শ কৰি ধৰি ৰাখক"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"আপোনাৰ স্ক্ৰীনখনত থকা সমল সন্ধান কৰিবলৈ কাৰ্য কীটো স্পৰ্শ কৰি ধৰি ৰাখক"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"এই প্ৰ’ডাক্টটোৱে সন্ধান কৰিবলৈ আপোনাৰ স্ক্ৰীনখনৰ বাছনি কৰা অংশ ব্যৱহাৰ কৰে। Googleৰ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>গোপনীয়তাৰ নীতি<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> আৰু <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>সেৱাৰ চৰ্তাৱলী<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> প্ৰযোজ্য।"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"আপোনাৰ স্ক্ৰীনখনত থকা সমল সন্ধান কৰিবলৈ কাৰ্য কীটো স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"এই প্ৰ’ডাক্টটোৱে সন্ধান কৰিবলৈ আপোনাৰ স্ক্ৰীনখনৰ বাছনি কৰা অংশ ব্যৱহাৰ কৰে। Googleৰ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>গোপনীয়তাৰ নীতি<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> আৰু <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>সেৱাৰ চৰ্তাৱলী<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> প্ৰযোজ্য।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হ’ল"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"গৃহপৃষ্ঠা"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্‌ দেখুৱাওক।}one{আৰু # টা এপ্‌ দেখুৱাওক।}other{আৰু # টা এপ্‌ দেখুৱাওক।}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ডেস্কটপত এপ্ যোগ দি থকা হৈছে"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"বাতিল কৰক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 68fcb3c..b30bf46 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tapşırıq paneli ilə daha çox şey edin"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"İşləmə panelini həmişə göstərin"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"İşləmə panelini həmişə ekranın aşağısında göstərmək üçün ayırıcı üzərinə toxunun və saxlayın"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekranda axtarış etmək üçün fəaliyyət açarına toxunub saxlayın"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu məhsul axtarış üçün ekranın seçilmiş hissəsindən istifadə edir. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Məxfilik Siyasəti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> və <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Xidmət Şərtləri<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> tətbiq edilir."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekranda axtarış etmək üçün fəaliyyət açarına toxunub saxlayın"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu məhsul axtarış üçün ekranın seçilmiş hissəsindən istifadə edir. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Məxfilik Siyasəti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> və <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Xidmət Şərtləri<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> tətbiq edilir."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Bağlayın"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hazırdır"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ev"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Tətbiqin masaüstünə əlavə edilməsi"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ləğv edin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 6fb8f01..9e437e7 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvek prikazuj traku zadataka"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi traka zadataka uvek bila prikazana u dnu ekrana, dodirnite i zadržite razdelnik"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite taster radnji da biste pretražili ono što je na ekranu"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod koristi izabrani deo ekrana za pretragu. Primenjuju se Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>politika privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uslovi korišćenja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite taster radnji da biste pretražili ono što je na ekranu"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod koristi izabrani deo ekrana za pretragu. Primenjuju se Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>politika privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uslovi korišćenja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodaje se aplikacija na radnu povrršinu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Otkaži"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 344a3e6..eed8863 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Выкарыстоўвайце магчымасці панэлі задач"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Замацуйце панэль задач унізе экрана"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для гэтага націсніце на раздзяляльнік і ўтрымлівайце яго"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Для пошуку па змесціве экрана націсніце і ўтрымлівайце клавішу дзеяння"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Гэты прадукт выконвае пошук па змесціве выбранай часткі экрана. Прымяняюцца <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Умовы выкарыстання<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> і <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Палітыка прыватнасці<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Гатова"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Галоўны экран"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Дадаванне праграмы на камп\'ютар"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Скасаваць"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 6ae8931..3c66e25 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повече неща с лентата на задачите"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Лентата на задачите да се показва винаги"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"За да фиксирате лентата на задачите най-долу на екрана, докоснете и задръжте разделителя"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Докоснете и задръжте клавиша за действия, за да извършите търсене със съдържанието на екрана"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Този продукт използва избраната част на екрана ви, за да търси. Прилагат се <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Декларацията за поверителност<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Общите условия<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> на Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Начало"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Приложението се добавя на настолния компютър"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Отказ"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index dec05ff..a0e32ef 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"\'টাস্কবার\' ফিচারের সাহায্যে আরও অনেক কিছু করুন"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবার সবসময় দেখানো"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"স্ক্রিনের নিচে টাস্কবার সবসময় দেখাতে ডিভাইডার টাচ করে ধরে থাকুন"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"আপনার স্ক্রিনে দেখতে পাওয়া কন্টেন্ট সার্চ করতে অ্যাকশন কী স্পর্শ করে ধরে রাখুন"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"সার্চ করার জন্য এই প্রোডাক্ট স্ক্রিনের বেছে নেওয়া অংশটুকু ব্যবহার করে। Google-এর <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>গোপনীয়তা নীতি<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> এবং <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>পরিষেবার শর্তাবলী<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> প্রযোজ্য।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ করুন"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হয়ে গেছে"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"হোম"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ডেস্কটপে অ্যাপ যোগ করা হচ্ছে"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"বাতিল করুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 83e4935..08dafca 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Radna površina"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz trake zadataka"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da se traka zadataka uvijek prikazuje na dnu ekrana, dodirnite i zadržite razdjelnik"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite tipku radnji da pretražite sadržaj na ekranu"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod koristi odabrani dio ekrana za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Pravila privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Uslovi korištenja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Dom"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Otkaži"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index d4c7d91..187d85a 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinador"</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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Treu més partit de la Barra de tasques"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la Barra de tasques"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Perquè es mostri sempre la Barra de tasques a la part inferior de la pantalla, mantén premut el separador"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén premuda la tecla d\'acció per cercar què es mostra a la pantalla"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>condicions del servei<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inici"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"S\'està afegint l\'aplicació a l\'ordinador"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel·la"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 743fc2b..ed32438 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Více možností s panelem aplikací"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stálé zobrazení panelu aplikací"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pokud chcete, aby se panel aplikací vždy zobrazoval ve spodní části obrazovky, podržte oddělovač."</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Podržením akční klávesy můžete vyhledat obsah na obrazovce"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Tato služba používá k vyhledávání vybranou část obrazovky. Platí <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>zásady ochrany soukromí<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> a <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>smluvní podmínky<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> společnosti Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Domů"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Přidání aplikace na plochu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Zrušit"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index cfe55cf..250a3d3 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computertilstand"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Få mere fra hånden med proceslinjen"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis altid proceslinjen"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Hvis du vil have, at proceslinjen altid vises nederst på din skærm, skal du holde fingeren på skillelinjen"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Hold fingeren på handlingstasten for at søge efter det, der vises på din skærm"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dette produkt bruger den valgte del af din skærm til at søge. Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privatlivspolitik<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>servicevilkår<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> er gældende."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Luk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Luk"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Appen føjes til computeren"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuller"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 1d012bb..af35fc3 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopmodus"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
@@ -96,7 +95,7 @@
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Teilen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
-    <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
+    <string name="action_split" msgid="2098009717623550676">"Splitscreen"</string>
     <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Mehr Möglichkeiten mit der Taskleiste"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskleiste immer anzeigen"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Damit die Taskleiste immer unten angezeigt wird, halte den Teiler gedrückt"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Aktionstaste gedrückt halten, um auf dem Bildschirm zu suchen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dieses Produkt verwendet den ausgewählten Teil deines Bildschirms für die Suche. Es gelten die <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Datenschutzerklärung<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> und die <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Nutzungsbedingungen<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> von Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fertig"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Startbildschirm"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Hinzufügen einer App zum Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Abbrechen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index ae3bef8..3bfe32a 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Κάντε περισσότερα με τη Γραμμή εργαλείων"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Να εμφανίζεται πάντα η Γραμμή εργαλείων"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Για να εμφανίζεται πάντα η Γραμμή εργαλείων στο κάτω μέρος της οθόνης, αγγίξτε παρατεταμένα το διαχωριστικό"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Αγγίξτε παρατεταμένα το πλήκτρο ενέργειας για να αναζητήσετε το περιεχόμενο της οθόνης"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Αυτό το προϊόν χρησιμοποιεί το επιλεγμένο τμήμα της οθόνης σας για αναζήτηση. Ισχύουν η <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Πολιτική απορρήτου<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> και οι <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Όροι Παροχής Υπηρεσιών<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> της Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Τέλος"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Αρχική σελίδα"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Γίνεται προσθήκη εφαρμογής στον υπολογιστή"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ακύρωση"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index fea224b..a26779c 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 37f4bce..9539da6 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch &amp; hold the action key to search what\'s on your screen"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch &amp; hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index fea224b..a26779c 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index fea224b..a26779c 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index c64c495..f3499e1 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎Desktop‎‏‎‎‏‎"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎Do more with the Taskbar‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎Always show the Taskbar‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider‎‏‎‎‏‎"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎Touch &amp; hold the action key to search what\'s on your screen‎‏‎‎‏‎"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎This product uses the selected part of your screen to search. Google\'s ‎‏‎‎‏‏‎<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Privacy Policy‎‏‎‎‏‏‎<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Terms of Service‎‏‎‎‏‏‎<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ apply.‎‏‎‎‏‎"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‎Touch &amp; hold the action key to search what\'s on your screen‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎This product uses the selected part of your screen to search. Google\'s ‎‏‎‎‏‏‎<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Privacy Policy‎‏‎‎‏‏‎<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Terms of Service‎‏‎‎‏‏‎<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ apply.‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎Close‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎Done‎‏‎‎‏‎"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎Home‎‏‎‎‏‎"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎Move to top/left‎‏‎‎‏‎"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎Move to bottom/right‎‏‎‎‏‎"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎Show # more app.‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎Show # more apps.‎‏‎‎‏‎}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎Show # desktop app.‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎Show # desktop apps.‎‏‎‎‏‎}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="APP_NAME_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎Adding app to Desktop‎‏‎‎‏‎"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎Cancel‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 244c23f..8214544 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cerrar todo"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Aprovecha mejor la Barra de tareas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la Barra de tareas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Mantén presionado el divisor para mostrar siempre la Barra de tareas en la parte inferior de la pantalla"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén presionada la tecla de acción para buscar qué hay en la pantalla"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de la pantalla para buscar. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> y las <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Condiciones del Servicio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Botón de inicio"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Agregando app al escritorio"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 1bab3ac..0d43f1e 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Sácale más partido a la barra de tareas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la barra de tareas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar siempre la barra de tareas en la parte inferior, mantén pulsada la línea divisoria"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> y los <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Añadiendo aplicación al ordenador"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 0a587d1..c445bc8 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Lauaarvuti režiim"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
@@ -91,12 +90,12 @@
     <string name="allset_title" msgid="5021126669778966707">"Valmis!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Avalehele liikumiseks pühkige üles"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Avakuvale liikumiseks puudutage avakuva nuppu"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Olete valmis oma seadet <xliff:g id="DEVICE">%1$s</xliff:g> kasutama"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> on nüüd kasutamiseks valmis"</string>
     <string name="default_device_name" msgid="6660656727127422487">"seade"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Jaga"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
-    <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
+    <string name="action_split" msgid="2098009717623550676">"Jaga pooleks"</string>
     <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tehke tegumiriba abil enamat"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Alati kuvatud tegumiriba"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Puudutage pikalt jaoturit, et tegumiriba oleks ekraani allosas alati kuvatud"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Puudutage pikalt toiminguklahvi, et ekraanil kuvatut otsida"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"See toode kasutab otsingu jaoks ekraani valitud osa. Kehtivad Google\'i <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privaatsuseeskirjad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ja <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>teenusetingimused<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sule"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Avaleht"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Rakenduse lisamine arvutisse"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Tühista"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index e10a085..3f56068 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenagailua"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Egin gauza gehiago zereginen barrarekin"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Erakutsi beti zereginen barra"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pantailaren behealdeko zereginen barra beti erakusteko, eduki sakatuta zatitzailea"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Eduki sakatuta ekintza-tekla pantailan dagoena bilatzeko"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produktu honek pantailan hautatutako zatia erabiltzen du bilaketa egiteko. Google-ren <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Pribatutasun-gidalerroak<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> eta <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Zerbitzu-baldintzak<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> aplikatzen dira."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Eginda"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hasiera"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Aplikazioa mahaigainean gehitzen"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Utzi"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 958eecc..b6db375 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"با «نوار وظیفه» می‌توانید کارهای بیشتر انجام دهید"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"همیشه نشان داده شدن «نوار وظیفه»"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"برای اینکه «نوار وظیفه» همیشه در پایین صفحه نشان داده شود، تقسیم‌کننده را لمس کنید و نگه دارید"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"برای جستجوی محتوای صفحه‌نمایش، دکمه کنش را لمس کنید و نگه دارید"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏این محصول از قسمت انتخاب‌شده صفحه‌نمایش شما برای جستجو استفاده می‌کند. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>خط‌مشی رازداری<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> و <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>شرایط خدمات<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google اعمال می‌شود."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"برای جستجوی محتوای صفحه‌نمایش، دکمه کنش را لمس کنید و نگه دارید"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"‏این محصول از قسمت انتخاب‌شده صفحه‌نمایش شما برای جستجو استفاده می‌کند. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>خط‌مشی رازداری<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> و <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>شرایط خدمات<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google اعمال می‌شود."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تمام"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"صفحه اصلی"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"درحال افزودن برنامه به رایانه"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"لغو"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index d4a0d83..040976d 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tietokone"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
@@ -96,7 +95,7 @@
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Järjestelmän navigointiasetukset"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Jaa"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
-    <string name="action_split" msgid="2098009717623550676">"Jaa"</string>
+    <string name="action_split" msgid="2098009717623550676">"Jaettu näyttö"</string>
     <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Vinkkejä tehtäväpalkin tehokkaampaan käyttöön"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Näytä tehtäväpalkki aina"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jos haluat tehtäväpalkin näkyvän aina näytön alaosassa, kosketa jakajaa pitkään"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Kosketa toimintonäppäintä pitkään, niin voit hakea näytöltä"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Tämä tuote käyttää hakuun valittua näytön osaa. Tähän sovelletaan Googlen <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>tietosuojakäytäntöä<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ja <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>käyttöehtoja<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Etusivu"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Sovelluksen lisääminen työpöydälle"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Peru"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 444bb83..9c30dc5 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la Barre des tâches"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la Barre des tâches en bas de l\'écran, maintenez le doigt sur le séparateur"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Maintenez le doigt sur la touche d\'action pour rechercher ce qui se trouve sur votre écran"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ce produit utilise la partie sélectionnée de votre écran pour effectuer une recherche. La <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>politique de confidentialité<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> et les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>conditions d\'utilisation<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google s\'appliquent."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre application.}one{Afficher # autre application.}other{Afficher # autres applications.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Ajout de l\'application au bureau en cours…"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuler"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 0d70416..72a6334 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la barre des tâches"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la barre des tâches en bas de votre écran, appuyez sur le séparateur de manière prolongée."</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Appuyez de manière prolongée sur la touche d\'action pour rechercher ce qui se trouve à l\'écran"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ce produit utilise la zone sélectionnée de l\'écran pour rechercher. Les <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Règles de confidentialité<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> et les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Conditions d\'utilisation<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google s\'appliquent."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Ajout de l\'appli au bureau"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuler"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index eadd73d..2c06c8f 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -21,8 +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 libre"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tira máis proveito da barra de tarefas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar sempre a barra de tarefas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para fixar a barra de tarefas na parte inferior, mantén premida a liña divisoria"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén premida a tecla de acción para buscar o que hai na pantalla"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este produto utiliza a parte seleccionada da pantalla para facer buscas. Aplícanse as <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Condicións de servizo<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> e a <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Engadindo aplicación ao ordenador"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 644240a..25285cb 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ટાસ્કબાર વડે બીજું ઘણું કરો"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ટાસ્કબાર હંમેશાં બતાવો"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ટાસ્કબાર હંમેશાં તમારી સ્ક્રીનમાં સૌથી નીચે દેખાય તે માટે વિભાજકને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"તમારી સ્ક્રીન પર જે હોય તે શોધવા માટે, ઍક્શન કી ટચ કરીને દબાવી રાખો"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"શોધવા માટે, આ પ્રોડક્ટ તમારી સ્ક્રીનના પસંદ કરેલા ભાગનો ઉપયોગ કરે છે. Googleની <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>પ્રાઇવસી પૉલિસી<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> અને <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>સેવાની શરતો<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> લાગુ થાય છે."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"તમારી સ્ક્રીન પર જે હોય તે શોધવા માટે, ઍક્શન કી ટચ કરીને દબાવી રાખો"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"શોધવા માટે, આ પ્રોડક્ટ તમારી સ્ક્રીનના પસંદ કરેલા ભાગનો ઉપયોગ કરે છે. Googleની <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>પ્રાઇવસી પૉલિસી<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> અને <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>સેવાની શરતો<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> લાગુ થાય છે."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"બંધ કરો"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"થઈ ગયું"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"હોમ"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ડેસ્કટૉપ પર ઍપ ઉમેરી રહ્યાં છીએ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"રદ કરો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index b2da5db..d40b0b4 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार के साथ कई और काम करें"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार को हमेशा दिखाएं"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार को हमेशा अपनी स्क्रीन के नीचे दिखाने के लिए, डिवाइडर दबाकर रखें"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"स्क्रीन में दिख रहे कॉन्टेंट को खोजने के लिए, ऐक्शन बटन को दबाकर रखें"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यह प्रॉडक्ट, कॉन्टेंट खोजने के लिए स्क्रीन पर चुनिंदा हिस्से का इस्तेमाल करता है. Google की <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>निजता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> और <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवा की शर्तें<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू होती हैं."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"स्क्रीन पर दिख रहे कॉन्टेंट को खोजने के लिए, ऐक्शन बटन को दबाकर रखें"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"यह प्रॉडक्ट, स्क्रीन के चुनिंदा हिस्से पर कॉन्टेंट खोजता है. Google की <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>निजता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> और <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवा की शर्तें<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"हो गया"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटॉप पर ऐप्लिकेशन जोड़ा जा रहा है"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द करें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index b68d961..6422f8d 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računalo"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
@@ -91,7 +90,7 @@
     <string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste za početak upotrebe uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> je spreman za početak upotrebe"</string>
     <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sustavom"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Podijeli"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Učinite više pomoću trake sa zadacima"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvijek prikazuj traku sa zadacima"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi se traka prikazivala, dodirnite i držite razdjelnik"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Odustani"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index e69bc53..7ce1f02 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Jobban kihasználhatja a Feladatsávot"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mindig jelenjen meg a Feladatsáv"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ahhoz, hogy a Feladatsáv mindig megjelenjen a képernyő alján, érintse meg és tartsa lenyomva az elválasztót"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"A műveletbillentyűt lenyomva tartva kereshet a képernyőn található tartalmak között"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ez a termék a képernyő kiválasztott részét használja a kereséshez. A Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Adatvédelmi irányelvei<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> és <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Általános Szerződési Feltételei<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> érvényesek."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Bezárás"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kész"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Kezdőlap"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Alkalmazás hozzáadása az asztalhoz"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Mégse"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 1889a4e..d35aba1 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Օգտվեք հավելվածների վահանակի բոլոր հնարավորություններից"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ամրացրեք հավելվածների վահանակը"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Հավելվածների վահանակն էկրանի ներքևում ամրացնելու համար հպեք և պահեք բաժանիչը"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Սեղմած պահեք գործողության ստեղնը՝ էկրանին բովանդակություն որոնելու համար"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Այս պրոդուկտն օգտագործում է էկրանի ընտրված հատվածը որոնման համար։ Կիրառվում են Google-ի <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>գաղտնիության քաղաքականությունը<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> և <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>օգտագործման պայմանները<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>։"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Պատրաստ է"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Սկիզբ"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Հավելվածն ավելացվում է աշխատասեղանին"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Չեղարկել"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index eec7e10..aaf6ced 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak hal dengan Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Selalu tampilkan Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk selalu menampilkan Taskbar di bagian bawah layar Anda, sentuh &amp; tahan pembatasnya"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh &amp; tahan tombol tindakan untuk mencari konten di layar Anda"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bagian layar terpilih untuk menelusuri. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Kebijakan Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Persyaratan Layanan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google berlaku."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Sentuh &amp; tahan tombol tindakan untuk mencari konten di layar Anda"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produk ini menggunakan bagian layar terpilih untuk menelusuri. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Kebijakan Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Persyaratan Layanan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google berlaku."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Layar utama"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan aplikasi ke Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batalkan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index e023124..d008af6 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Nýttu forritastikuna betur"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Halda forritastikunni sýnilegri"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Haltu skjáskiptingunni neðst á skjánum inni til að halda forritastikunni sýnilegri"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Haltu aðgerðalyklinum inni til að leita að því sem er á skjánum"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Þessi vara notar valinn hluta skjásins til að leita. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Persónuverndarstefna<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>þjónustuskilmálar<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google gilda."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Haltu aðgerðalyklinum inni til að leita að því sem er á skjánum"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Þessi vara notar valinn hluta skjásins til að leita. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Persónuverndarstefna<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>þjónustuskilmálar<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google gilda."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Loka"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Lokið"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Heim"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Forriti bætt við skjáborð"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Hætta við"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index aeeb6a2..207c182 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Fai di più con la barra delle app"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la barra delle app"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Per mostrare sempre la barra delle app in basso, tocca e tieni premuto il divisore"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Tocca e tieni premuto il tasto azione per cercare gli elementi sullo schermo"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Il prodotto usa la parte selezionata dello schermo per cercare. Si applicano le <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Norme sulla privacy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termini di servizio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> di Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fine"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Aggiunta app a desktop in corso…"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annulla"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 3899f67..9be2c1a 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"פעולות נוספות שאפשר לעשות עם סרגל האפליקציות"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"תמיד להציג את סרגל האפליקציות"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"כדי להציג תמיד את סרגל האפליקציות בתחתית המסך, יש ללחוץ לחיצה ארוכה על המחיצה"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"כדי לחפש במסך, צריך ללחוץ לחיצה ארוכה על מקש הפעולה"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"‏המוצר הזה משתמש בחלק שבחרת במסך לצורך חיפוש, בכפוף ל<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>מדיניות הפרטיות<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ו<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>לתנאים ולהגבלות<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> של Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"סיום"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"בית"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"האפליקציה מתווספת לשולחן העבודה"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ביטול"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 8125ea4..084f2b2 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"タスクバーの各種機能"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"タスクバーを常に表示"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"タスクバーを画面下部に常に表示するには分割線を長押しします"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"画面上の内容を検索するには、アクションキーを長押ししてください"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"このサービスは、検索する際に画面上で選択された箇所を使用します。Google の<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>プライバシー ポリシー<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>と<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>利用規約<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>が適用されます。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完了"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ホーム"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"アプリをデスクトップに追加する"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"キャンセル"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 14c0773..b6890c4 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"გააკეთეთ მეტი ამოცანათა ზოლის მეშვეობით"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ამოცანათა ზოლის მუდმივად ჩვენება"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"თქვენი ეკრანის ქვედა ნაწილში ამოცანათა ზოლის მუდმივად საჩვენებლად, ხანგრძლივად შეეხეთ გამყოფს"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"შეეხეთ და გეჭიროთ მოქმედების ღილაკი, რათა მოძებნოთ ის, რაც თქვენს ეკრანზეა"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ეს პროდუქტი ძიებისთვის იყენებს თქვენი ეკრანის არჩეულ ნაწილს. მოქმედებს Google-ის <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>კონფიდენციალურობის დებულება<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> და <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>მომსახურებს პირობები<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"მზადაა"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"მთავარი"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"მიმდინარეობს აპის დესკტოპზე დამატება"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"გაუქმება"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 9964105..36f3490 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапсырмалар жолағын әрдайым көрсету"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Экранның төменгі жағында тапсырмалар жолағы әрдайым көрсетілуі үшін, бөлгішті басып тұрыңыз."</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Бұл өнім іздеу үшін экранның таңдалған бөлігін пайдаланады. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Құпиялық саясаты<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> мен <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Қызмет көрсету шарттары<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> қолданылады."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Негізгі экран"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Жұмыс үстеліне қолданба қосу"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Бас тарту"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 3b7180c..98a97e7 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ធ្វើបានកាន់តែច្រើនដោយប្រើរបារកិច្ចការ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ដើម្បីបង្ហាញរបារកិច្ចការនៅផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នកជានិច្ច សូមចុចបន្ទាត់ខណ្ឌចែកឱ្យជាប់"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ចុចគ្រាប់ចុចសកម្មភាពឱ្យជាប់ ដើម្បីស្វែងរកអ្វីដែលមាននៅលើអេក្រង់របស់អ្នក"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ផលិតផលនេះប្រើប្រាស់ផ្នែកដែលបានជ្រើសរើសនៃអេក្រង់របស់អ្នក ដើម្បីស្វែងរក។ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>គោលការណ៍​ឯកជនភាព<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> និង<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>លក្ខខណ្ឌ​ប្រើប្រាស់<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>របស់ Google ត្រូវបានអនុវត្ត។"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ចុចគ្រាប់ចុចសកម្មភាពឱ្យជាប់ ដើម្បីស្វែងរកអ្វីដែលមាននៅលើអេក្រង់របស់អ្នក"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ផលិតផលនេះប្រើប្រាស់ផ្នែកដែលបានជ្រើសរើសនៃអេក្រង់របស់អ្នក ដើម្បីស្វែងរក។ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>គោលការណ៍​ឯកជនភាព<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> និង<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>លក្ខខណ្ឌ​ប្រើប្រាស់<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>របស់ Google ត្រូវបានអនុវត្ត។"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"រួចរាល់"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ទំព័រដើម"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញ​កម្មវិធី # ទៀត។}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធី​កុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធី​កុំព្យូទ័រ #។}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"កំពុងបញ្ចូល​កម្មវិធីទៅកុំព្យូទ័រ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"បោះបង់"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 688098c..7b1241f 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ಟಾಸ್ಕ್‌ಬಾರ್ ಮೂಲಕ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್‌ಬಾರ್ ಅನ್ನು ತೋರಿಸಿ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಲ್ಲಿ ಟಾಸ್ಕ್ ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು, ಡಿವೈಡರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಏನಿದೆ ಎಂಬುದನ್ನು ಹುಡುಕಲು ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ಈ ಉತ್ಪನ್ನವು ಹುಡುಕಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಆಯ್ದ ಭಾಗವನ್ನು ಬಳಸುತ್ತದೆ. Google ನ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ಗೌಪ್ಯತೆ ನೀತಿ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ಮತ್ತು <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ಸೇವಾ ನಿಯಮಗಳು<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ಅನ್ವಯಿಸುತ್ತವೆ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ಆಯಿತು"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ಮುಖಪುಟ"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್‌ಟಾಪ್ ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ಗೆ ಆ್ಯಪ್ ಅನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ರದ್ದುಮಾಡಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index b8a131a..5f05968 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"태스크 바 최대한 활용하기"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"태스크 바 항상 표시"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"화면 하단에 태스크 바를 항상 표시하려면 구분선을 길게 터치하세요."</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"화면 내용을 검색하려면 작업 키 길게 터치"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"이 제품은 사용자가 화면에서 선택한 부분을 사용하여 검색하며, Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>개인정보처리방침<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> 및 <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>서비스 약관<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>이 적용됩니다."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"완료"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"홈"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"데스크톱에 앱 추가하기"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"취소"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 061952c..993e4ea 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар тактасы менен көбүрөөк иш бүтүрөсүз"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапшырмалар панелин ар дайым көрсөтүү"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Тапшырмалар панелин экрандын ылдый жагында ар дайым көрсөтүү үчүн бөлгүчтү коё бербей басыңыз"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экрандагы нерсени издөө үчүн аракет баскычын коё бербей кармап туруңуз"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бул кызмат издөө үчүн экранда тандалган бөлүктү колдонот. Google\'дун <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Купуялык эрежелери<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> жана <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Тейлөө шарттары<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> колдонулат."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Экрандагы нерсени издөө үчүн аракет баскычын коё бербей кармап туруңуз"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Бул кызмат издөө үчүн экранда тандалган бөлүктү колдонот. Google\'дун <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Купуялык эрежелери<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> жана <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Тейлөө шарттары<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> колдонулат."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Бүттү"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Башкы бет"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Колдонмону иш тактага кошуу"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Жокко чыгаруу"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 211e9ed..2d5a5cc 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ເຮັດສິ່ງຕ່າງໆໄດ້ຫຼາຍຂຶ້ນດ້ວຍແຖບໜ້າວຽກ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ເພື່ອໃຫ້ແຖບໜ້າວຽກສະແດງຢູ່ລຸ່ມໜ້າຈໍຂອງທ່ານຢູ່ສະເໝີ, ໃຫ້ແຕະຕົວແບ່ງຄ້າງໄວ້"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ແຕະປຸ່ມຄຳສັ່ງຄ້າງໄວ້ເພື່ອຊອກຫາສິ່ງທີ່ຢູ່ເທິງໜ້າຈໍຂອງທ່ານ"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ສິນຄ້ານີ້ໃຊ້ສ່ວນທີ່ເລືອກຂອງໜ້າຈໍຂອງທ່ານເພື່ອຊອກຫາ. ເປັນໄປຕາມ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ນະໂຍບາຍຄວາມເປັນສ່ວນຕົວ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ແລະ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ຂໍ້ກຳນົດບໍລິການ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ຂອງ Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ແຕະປຸ່ມຄຳສັ່ງຄ້າງໄວ້ເພື່ອຊອກຫາສິ່ງທີ່ຢູ່ເທິງໜ້າຈໍຂອງທ່ານ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ສິນຄ້ານີ້ໃຊ້ສ່ວນທີ່ເລືອກຂອງໜ້າຈໍຂອງທ່ານເພື່ອຊອກຫາ. ເປັນໄປຕາມ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ນະໂຍບາຍຄວາມເປັນສ່ວນຕົວ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ແລະ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ຂໍ້ກຳນົດບໍລິການ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ຂອງ Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ແລ້ວໆ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ໜ້າຫຼັກ"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ການເພີ່ມແອັບໄປໃສ່ເດັສທັອບ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ຍົກເລີກ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index e2f1af9..232e7e7 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Atlikite daugiau naudodami Užduočių juostą"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visada rodyti užduočių juostą"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jei norite, kad užduočių juosta visada būtų rodoma ekrano apačioje, palieskite ir palaikykite daliklį"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekrane rodomo turinio paieška palietus ir laikant veiksmų klavišą"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Šis produktas paieškai naudoja pasirinktą ekrano dalį. Taikomos „Google“ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privatumo politikos<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ir <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>paslaugų teikimo sąlygos<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Uždaryti"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Atlikta"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Pagrindinis"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Pridedama programa prie darbalaukio"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Atšaukti"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 6881a09..d602676 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Dators"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Plašākas iespējas, izmantojot uzdevumu joslu"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vienmēr rādīt uzdevumu joslu"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Lai uzdevumu joslu rādītu apakšdaļā, pieskarieties atdalītājam un turiet"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Pieskarieties darbību taustiņam un turiet to, lai meklētu ekrānā redzamo saturu"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Šajā produktā atlasītā ekrāna daļa tiek izmantota meklēšanai. Ir spēkā Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>konfidencialitātes politika<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> un <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>pakalpojumu sniegšanas noteikumi<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gatavs"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Sākums"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Notiek lietotnes pievienošana datoram"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Atcelt"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 6408a4d..3d1196a 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете сешто со „Лентата со задачи“"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Како секогаш да се прикажува „Лентата со задачи“"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Допрете и задржете го разделникот за да може „Лентата со задачи“ секогаш да се прикажува на дното на екранот"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Допрете и задржете го копчето за дејство за да пребарувате на екранот"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Производов го користи избраниот дел од екранот за пребарување. Важат <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Политиката за приватност<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Условите за користење<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> на Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Дома"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Додавање на апликацијата во „Работна површина“"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Откажи"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 17380a0..8194897 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ടാസ്‌ക്‌ബാർ ഉപയോഗിച്ച് കൂടുതൽ ചെയ്യുക"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"എല്ലായ്‌പ്പോഴും ടാസ്‌ക്‌ബാർ കാണിക്കുക"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ടാസ്‌ക്ബാർ എല്ലായ്‌പ്പോഴും നിങ്ങളുടെ സ്‌ക്രീനിന്റെ ചുവടെ കാണിക്കുന്നതിന് ഡിവൈഡറിൽ സ്‌പർശിച്ച് പിടിക്കുക"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"നിങ്ങളുടെ സ്‌ക്രീനിൽ എന്താണ് ഉള്ളതെന്ന് തിരയാൻ ആക്ഷൻ കീ സ്‌പർശിച്ച് പിടിക്കുക"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"തിരയുന്നതിന് ഈ ഉൽപ്പന്നം സ്‌ക്രീനിലെ തിരഞ്ഞെടുത്ത ഭാഗം ഉപയോഗിക്കുന്നു. Google-ന്റെ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>സ്വകാര്യതാ നയവും<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>സേവന നിബന്ധനകളും<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ബാധകമാണ്."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"നിങ്ങളുടെ സ്‌ക്രീനിൽ എന്താണ് ഉള്ളതെന്ന് തിരയാൻ ആക്ഷൻ കീ സ്‌പർശിച്ച് പിടിക്കുക"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"തിരയുന്നതിന് ഈ ഉൽപ്പന്നം സ്‌ക്രീനിലെ തിരഞ്ഞെടുത്ത ഭാഗം ഉപയോഗിക്കുന്നു. Google-ന്റെ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>സ്വകാര്യതാ നയവും<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>സേവന നിബന്ധനകളും<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ബാധകമാണ്."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"പൂർത്തിയായി"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ഹോം"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്‌ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്‌ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ആപ്പ് ഡെസ്ക്ടോപ്പിലേക്ക് ചേർക്കുന്നു"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"റദ്ദാക്കുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index bc6a43b..7b4337c 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Ажлын хэсгийн тусламжтай илүү ихийг хийгээрэй"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ажлын хэсгийг үргэлж харуулах"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Дэлгэцийнхээ доод талд Ажлын хэсгийг үргэлж харуулахын тулд хуваагч дээр хүрээд удаан дарна уу"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Дэлгэц дээрээ байгаа зүйлийг хайхын тулд тусгай товчлуурыг удаан дарна уу"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Энэ бүтээгдэхүүн хайхын тулд таны дэлгэцийн сонгосон хэсгийг ашигладаг. Google-н <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>нууцлалын бодлого<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> болон <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>үйлчилгээний нөхцөл<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> хэрэгжинэ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дууссан"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Гэр"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Компьютерт апп нэмж байна"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Цуцлах"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index b0c6aca..453de89 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार चा पुरेपूर वापर करा"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार नेहमी दाखवा"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार नेहमी तुमच्या स्क्रीनच्या तळाशी दाखवण्यासाठी, विभाजकाला स्पर्श करून धरून ठेवा"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"तुमच्या स्क्रीनवरील गोष्टी शोधण्यासाठी अ‍ॅक्शन की स्पर्श करून धरून ठेवा"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"हे उत्पादन शोधण्याच्या हेतूसाठी तुमच्या स्क्रीनचा निवडक भाग वापरते. Google चे <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>गोपनीयता धोरण<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> आणि <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवा अटी<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू होतात."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करा"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"पूर्ण झाले"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{आणखी # अ‍ॅप दाखवा.}other{आणखी # अ‍ॅप्स दाखवा.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्‍कटॉप अ‍ॅप दाखवा.}other{# डेस्‍कटॉप अ‍ॅप्स दाखवा.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटॉपवर ॲप जोडत आहे"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द करा"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 87c6e24..cbc1594 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak perkara dengan Bar Tugas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sentiasa paparkan Bar Tugas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk sentiasa memaparkan Bar Tugas pada bahagian bawah skrin, sentuh &amp; tahan pembahagi"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh &amp; tahan kekunci tindakan untuk mencari kandungan yang dipaparkan pada skrin anda"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bahagian yang dipilih pada skrin untuk membuat carian. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Dasar Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Syarat Perkhidmatan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google digunakan."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Sentuh &amp; tahan kekunci tindakan untuk mencari kandungan yang dipaparkan pada skrin anda"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produk ini menggunakan bahagian yang dipilih pada skrin anda untuk membuat carian. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Dasar Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Syarat Perkhidmatan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google digunakan."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Laman Utama"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan apl pada Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batal"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index d7c98d3..ecde5a3 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -96,7 +95,7 @@
     <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_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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Taskbar ဖြင့် ပိုမိုလုပ်ဆောင်နိုင်ခြင်း"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskbar ကို အမြဲပြပါ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Taskbar ကို စခရင်အောက်ခြေတွင် အမြဲပြရန် ခွဲခြားမျဉ်းကို တို့ထိ၍ ဖိထားပါ"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"သင့်စခရင်ပေါ်ရှိအရာကို ရှာရန် လုပ်ဆောင်ချက်ကီးကို ထိ၍ဖိထားပါ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ဤကုန်ပစ္စည်းသည် သင့်စခရင်၌ ရွေးထားသောအပိုင်းကိုသုံး၍ ရှာဖွေသည်။ Google ၏ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ကိုယ်ရေးအချက်အလက်လုံခြုံမှုဆိုင်ရာ မူဝါဒ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> နှင့် <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ဝန်ဆောင်မှုစည်းမျဉ်းများ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> အကျုံးဝင်သည်။"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ပြီးပြီ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ပင်မစာမျက်နှာ"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"‘ဒက်စ်တော့’ တွင် အက်ပ်ကို ထည့်ခြင်း"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"မလုပ်တော့"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 550bacc..5ea50f4 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Gjør mer med oppgavelinjen"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis alltid oppgavelinjen"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"For å alltid vise oppgavelinjen nederst på skjermen, trykk og hold på skillelinjen"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Trykk og hold på handlingstasten for å søke etter det som er på skjermen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dette produktet bruker den merkede delen av skjermen til å søke. Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>personvernregler<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>vilkår for bruk<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> gjelder."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Lukk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Ferdig"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Legg til apper på datamaskin"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Avbryt"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index acfa2ce..38df28b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार प्रयोग गरेर अझ धेरै कार्य गर्नुहोस्"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार सधैँ देखाउनुहोस्"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"आफ्नो स्क्रिनको पुछारमा टास्कबार सधैँ देखाइराख्न डिभाइडर टच एन्ड होल्ड गर्नुहोस्"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"आफ्नो स्क्रिनमा भएका कुराहरू खोज्न एक्सन कीमा टच एण्ड होल्ड गर्नुहोस्"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यो उत्पादनले तपाईंले चयन गर्नुभएको स्क्रिनको भाग प्रयोग गरेर खोजी गर्छ। Google को <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>गोपनीयता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> र <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवाका सर्तहरू<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू हुन्छन्।"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"आफ्नो स्क्रिनमा भएका कुराहरू खोज्न एक्सन कीमा टच एन्ड होल्ड गर्नुहोस्"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"यो उत्पादनले तपाईंले चयन गर्नुभएको स्क्रिनको भाग प्रयोग गरेर खोजी गर्छ। Google को <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>गोपनीयता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> र <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवाका सर्तहरू<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू हुन्छन्।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बन्द गर्नुहोस्"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"सम्पन्न भयो"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटपमा एप हालिँदै छ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द गर्नुहोस्"</string>
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index ed0bd5b..401351f 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -25,6 +25,21 @@
         <item name="android:windowBackground">@android:color/transparent</item>
     </style>
 
+    <style name="TextAppearance.GestureTutorial.MainTitle.Home"
+        parent="TextAppearance.GestureTutorial.MainTitle">
+        <item name="android:textColor">?attr/onSurfaceHome</item>
+    </style>
+
+    <style name="TextAppearance.GestureTutorial.MainTitle.Back"
+        parent="TextAppearance.GestureTutorial.MainTitle">
+        <item name="android:textColor">?attr/onSurfaceBack</item>
+    </style>
+
+    <style name="TextAppearance.GestureTutorial.MainTitle.Overview"
+        parent="TextAppearance.GestureTutorial.MainTitle">
+        <item name="android:textColor">?attr/onSurfaceOverview</item>
+    </style>
+
     <style name="TextAppearance.GestureTutorial.MenuButton.Home"
         parent="TextAppearance.GestureTutorial.MenuButton">
         <item name="android:textColor">?attr/onSurfaceHome</item>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 3032ade..fc435f8 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Doe meer met de taakbalk"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"De taakbalk altijd tonen"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Houd de scheidingslijn ingedrukt als je de taakbalk altijd onderaan je scherm wilt tonen"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Houd je vinger op de actietoets om te zoeken naar wat er op je scherm staat"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dit product gebruikt het geselecteerde gedeelte van je scherm om te zoeken. Het <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacybeleid<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> en de <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Servicevoorwaarden<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> van Google zijn van toepassing."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sluiten"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"App toevoegen aan desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuleren"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index a67cff9..2069e30 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ଟାସ୍କବାର ମାଧ୍ୟମରେ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ନିମ୍ନରେ ସର୍ବଦା ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଡିଭାଇଡରକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ କଣ ଅଛି ତାହା ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଆକ୍ସନ କୀ\'କୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଏହି ପ୍ରଡକ୍ଟ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଚୟନିତ ଅଂଶକୁ ବ୍ୟବହାର କରେ। Googleର <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ଗୋପନୀୟତା ନୀତି<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ଏବଂ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ସେବାର ସର୍ତ୍ତାବଳୀ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ଲାଗୁ ହୁଏ।"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ କଣ ଅଛି ତାହା ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଆକ୍ସନ କୀ\'କୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଏହି ପ୍ରଡକ୍ଟ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଚୟନିତ ଅଂଶକୁ ବ୍ୟବହାର କରେ। Googleର <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ଗୋପନୀୟତା ନୀତି<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ଏବଂ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ସେବାର ସର୍ତ୍ତାବଳୀ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ଲାଗୁ ହୁଏ।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ହୋଇଗଲା"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ହୋମ"</string>
@@ -128,7 +127,7 @@
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ସ୍ୱିଚର"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"ବର୍ତ୍ତମାନର"</string>
     <string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
-    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string>
+    <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>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ଡେସ୍କଟପରେ ଆପ ଯୋଗ କରାଯାଉଛି"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ବାତିଲ କରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 38d2dac..58544a8 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ਟਾਸਕਬਾਰ ਦਾ ਹੋਰ ਲਾਹਾ ਲਓ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣਾ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ, ਵਿਭਾਜਕ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਮੌਜੂਦ ਸਮੱਗਰੀ ਨੂੰ ਖੋਜਣ ਲਈ, ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ਇਹ ਉਤਪਾਦ ਖੋਜ ਕਰਨ ਲਈ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਚੁਣੇ ਹੋਏ ਹਿੱਸੇ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। Google ਦੀ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ਪਰਦੇਦਾਰੀ ਨੀਤੀ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ਅਤੇ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ਸੇਵਾ ਦੇ ਨਿਯਮ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ਲਾਗੂ ਹੁੰਦੇ ਹਨ।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ਸਮਝ ਲਿਆ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ਘਰ"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ਐਪ ਨੂੰ ਡੈਸਕਟਾਪ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ਰੱਦ ਕਰੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 9a55b94..0f55f11 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Pulpit"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
@@ -91,7 +90,7 @@
     <string name="allset_title" msgid="5021126669778966707">"Wszystko gotowe"</string>
     <string name="allset_hint" msgid="459504134589971527">"Aby przejść na stronę główną, przesuń w górę"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Kliknij przycisk ekranu głównego, aby otworzyć ekran główny"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Teraz możesz zacząć używać urządzenia <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> jest gotowe – możesz zacząć z niego korzystać"</string>
     <string name="default_device_name" msgid="6660656727127422487">"urządzenie"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ustawienia nawigacji w systemie"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Wykorzystaj potencjał paska aplikacji"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Zawsze wyświetlaj pasek aplikacji"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Aby zawsze wyświetlać pasek aplikacji u dołu ekranu, naciśnij i przytrzymaj linię dzielenia ekranu"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Aby rozpocząć wyszukiwanie na podstawie zawartości ekranu, naciśnij i przytrzymaj klawisz działania"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Usługa przy wyszukiwaniu używa zaznaczonego fragmentu ekranu. Obowiązują zapisy <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Polityki prywatności<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Warunków korzystania z usług<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Aby rozpocząć wyszukiwanie na podstawie zawartości ekranu, naciśnij i przytrzymaj klawisz działania"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Usługa przy wyszukiwaniu używa zaznaczonego fragmentu ekranu. Obowiązują zapisy <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Polityki prywatności<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Warunków korzystania z usług<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zamknij"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotowe"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ekran główny"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodaję aplikację do komputera"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anuluj"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 202813b..761329a 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faça mais com a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostre sempre a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar sempre a Barra de tarefas no fundo do ecrã, toque sem soltar no divisor"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Toque sem soltar na tecla de ação para pesquisar o que está no ecrã"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este produto usa a parte selecionada do ecrã para pesquisar. Aplicam-se a <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e os <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termos de Utilização<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> da Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Toque sem soltar na tecla de ação para pesquisar o que está no ecrã"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este produto usa a parte selecionada do ecrã para pesquisar. Aplicam-se a <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e os <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termos de Utilização<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> da Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluir"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"A adicionar a app ao computador"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 532a598..a105087 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Remover tudo"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Aproveite ainda mais a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sempre mostrar a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Toque e pressione o divisor para sempre mostrar a Barra de tarefas na parte de baixo da tela"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Toque na tecla de ação e pressione para pesquisar o que está na tela"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"O produto usa a parte selecionada da tela para pesquisar. O uso desses dados está sujeito à <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e aos <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termos de Serviço<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> do Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluído"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Adicionando app ao computador"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index ed7dfd8..d5ab773 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computer"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Șterge tot"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Fă mai multe din Bara de activități"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Afișează întotdeauna Bara de activități"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pentru a afișa mereu Bara de activități în partea de jos a ecranului, atinge lung separatorul"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Atinge lung tasta de acțiuni ca să cauți pe ecran"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Acest produs folosește partea selectată a ecranului pentru a căuta. Se aplică <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Politica de confidențialitate<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> și <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termenii și condițiile<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Închide"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gata"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ecran de pornire"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Se adaugă aplicația pe computer"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anulează"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 6f1d9e7..c03d847 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Используйте все возможности панели задач"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Закрепите панель задач внизу экрана"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для этого нажмите на разделитель и удерживайте его."</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Чтобы найти информацию об объекте на экране, нажмите и удерживайте клавишу действия"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Этот продукт использует выделенную часть экрана для поиска. При этом действуют <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Политика конфиденциальности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Условия использования<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Чтобы найти информацию об объекте на экране, нажмите и удерживайте клавишу действия"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Этот продукт использует выделенную часть экрана для поиска. При этом действуют <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Политика конфиденциальности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Условия использования<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Главный экран"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Добавление приложения на компьютер"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Отмена"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 1335e0e..7b3fd6d 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"කාර්ය තීරුව සමග තවත් කරන්න"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"සෑම විටම ඔබේ තිරයේ පතුලේ ඇති කාර්ය තීරුව පෙන්වීමට, බෙදුම්කරු ස්පර්ශ කර අල්ලාගෙන සිටින්න"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ඔබේ තිරයෙහි ඇති දේ සෙවීමට ක්‍රියා යතුර ස්පර්ශ කර සිටින්න"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"මෙම නිෂ්පාදනය සෙවීමට ඔබේ තිරයෙහි තෝරන ලද කොටස භාවිතා කරයි. Google හි <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>පෞද්ගලිකත්ව ප්‍රතිපත්තිය<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> සහ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>සේවා නියමයන්<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> අදාළ වේ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"නිමයි"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"මුල් පිටුව"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ඩෙස්ක්ටොප් වෙත යෙදුම එක් කිරීම"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"අවලංගු කරන්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 48f7a9c..0b40961 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Panel aplikácií vám ponúka ďalšie možnosti"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vždy zobrazovať panel aplikácií"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ak chcete, aby sa panel aplikácií vždy zobrazoval v dolnej časti obrazovky, pridržte rozdeľovač"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ak chcete vyhľadávať, čo je na obrazovke, pridržte akčný kláves."</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Táto služba používa na účely vyhľadávania vybranú časť obrazovky. Uplatňujú sa <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravidlá ochrany súkromia<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> a <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>zmluvné podmienky<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> spoločnosti Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ak chcete vyhľadávať, čo je na obrazovke, pridržte akčný kláves."</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Táto služba používa na účely vyhľadávania vybranú časť obrazovky. Uplatňujú sa <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravidlá ochrany súkromia<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> a <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>zmluvné podmienky<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> spoločnosti Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Plocha"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Pridanie aplikácie na plochu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Zrušiť"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 58e34f2..da290fc 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Namizni računalnik"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Naredite več z opravilno vrstico"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz opravilne vrstice"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Če želite, da je opravilna vrstica vedno prikazana na dnu zaslona, pridržite razdelilno črto."</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Za iskanje po zaslonu se dotaknite in pridržite tipko za dejanja"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ta izdelek za iskanje uporablja izbrani del zaslona. Veljajo Googlov <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravilnik o zasebnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> in <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>pogoji storitve<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Za iskanje po zaslonu se dotaknite in pridržite tipko za dejanja"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ta izdelek za iskanje uporablja izbrani del zaslona. Veljajo Googlov <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravilnik o zasebnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> in <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>pogoji storitve<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zapri"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Končano"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Začetni zaslon"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodajanje aplikacije na namizje"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Prekliči"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 1cc11d2..1b2db75 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopi"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Bëj më shumë me \"Shiritin e detyrave\""</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Shfaq gjithmonë \"Shiritin e detyrave\""</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Prek e mbaj ndarësin dhe shfaq gjithmonë \"Shiritin e detyrave\" në fund të ekranit"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Prek dhe mbaj shtypur tastin e veprimit për të kërkuar për gjërat në ekran"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ky produkt përdor pjesën e zgjedhur të ekranit tënd për të kërkuar. Zbatohen <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Politika e privatësisë<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dhe <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Kushtet e shërbimit<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> të Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Mbyll"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"U krye"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Faqja kryesore"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Shtimi i aplikacionit te desktopi"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anulo"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 0164d67..56e2c91 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Урадите више помоћу траке задатака"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Увек приказуј траку задатака"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Да би трака задатака увек била приказана у дну екрана, додирните и задржите разделник"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Додирните и задржите тастер радњи да бисте претражили оно што је на екрану"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Овај производ користи изабрани део екрана за претрагу. Примењују се Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>политика приватности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>услови коришћења услуге<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Додирните и задржите тастер радњи да бисте претражили оно што је на екрану"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Овај производ користи изабрани део екрана за претрагу. Примењују се Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>политика приватности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>услови коришћења услуге<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Почетна"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Додаје се апликација на радну поврршину"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Откажи"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index d994ef5..2a1eea6 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Dator"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Listan är tom"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Gör mer med aktivitetsfältet"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visa alltid aktivitetsfältet"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Tryck länge på avgränsaren för att alltid visa aktivitetsfältet längst ned på skärmen"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Tryck länge på åtgärdstangenten för att söka efter det som finns på skärmen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Den här produkten använder den valda delen av skärmen för att söka. Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>integritetspolicy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> och <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>användarvillkor<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> gäller."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Startsida"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Lägger till appen på skrivbordet"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Avbryt"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 9d925a5..329f332 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Kamilisha mengi kwa kutumia Upauzana huu"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Onyesha Upauzana kila wakati"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ili uonyeshe Upauzana kila wakati chini ya skrini yako, gusa na ushikilie kitenganishi"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Gusa na ushikilie kitufe cha vitendo ili utafute kilicho kwenye skrini yako"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bidhaa hii hutumia sehemu uliyochagua kwenye skrini yako kutafuta. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Sera ya Faragha<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> na <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Sheria na Masharti<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ya Google yatatumika."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Gusa na ushikilie kitufe cha vitendo ili utafute kilicho kwenye skrini yako"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bidhaa hii hutumia sehemu uliyochagua kwenye skrini yako kutafuta. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Sera ya Faragha<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> na <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Sheria na Masharti<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ya Google yatatumika."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Imemaliza"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Mwanzo"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Kuweka programu kwenye Eneo-kazi"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ghairi"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 2f458f4..4598925 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"செயல் பட்டி மூலம் மேலும் பலவற்றைச் செய்யுங்கள்"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"செயல் பட்டியை எப்போதும் காட்டுதல்"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"திரையின் கீழ்ப்பகுதியில் செயல் பட்டியை எப்போதும் காட்டுவதற்கு, பிரிப்பானைத் தொட்டுப் பிடித்திருக்கவும்"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"உங்கள் திரையில் உள்ளவற்றைத் தேடுவதற்கு ஆக்ஷன் பட்டனைத் தொட்டுப் பிடியுங்கள்"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"தேடுவதற்கு உங்கள் திரையின் தேர்ந்தெடுக்கப்பட்ட பகுதியை இந்தத் தயாரிப்பு பயன்படுத்துகிறது. Googleளின் <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>தனியுரிமைக் கொள்கையும்<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>சேவை விதிமுறைகளும்<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> பொருந்தும்."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"முடிந்தது"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"முகப்பு"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ஆப்ஸை டெஸ்க்டாப்பில் சேர்க்கிறது"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ரத்துசெய்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 5f1feff..49d2b9b 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"టాస్క్‌బార్‌తో మరిన్ని చేయండి"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"టాస్క్‌బార్‌ను నిరంతరం చూపండి"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"మీ స్క్రీన్ దిగువున టాస్క్‌బార్‌ను నిరంతరం చూపడానికి, డివైడర్‌ను తాకి, నొక్కి ఉంచండి"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"మీ స్క్రీన్‌లో ఏం ఉందో సెర్చ్ చేయడానికి యాక్షన్ కీని తాకి ఉంచండి"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ఈ ప్రోడక్ట్, సెర్చ్ చేయడానికి మీ స్క్రీన్‌లో ఎంచుకున్న భాగాన్ని ఉపయోగిస్తుంది. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>గోప్యతా పాలసీ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>, <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>సర్వీస్ నియమాలు<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> వర్తిస్తాయి."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"మీ స్క్రీన్‌లో ఏం ఉందో సెర్చ్ చేయడానికి యాక్షన్ కీని తాకి ఉంచండి"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ఈ ప్రోడక్ట్, సెర్చ్ చేయడానికి మీ స్క్రీన్‌లో ఎంచుకున్న భాగాన్ని ఉపయోగిస్తుంది. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>గోప్యతా పాలసీ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>, <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>సర్వీస్ నియమాలు<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> వర్తిస్తాయి."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"మూసివేయండి"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"పూర్తయింది"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"మొదటి ట్యాబ్"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{మరో # యాప్‌ను చూడండి.}other{మరో # యాప్‌లను చూడండి.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్‌టాప్ యాప్‌ను చూపండి.}other{# డెస్క్‌టాప్ యాప్‌లను చూపండి.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"డెస్క్‌టాప్‌నకు యాప్‌ను జోడిస్తోంది"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"రద్దు చేయండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index ea6a285..14a8741 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -93,7 +92,7 @@
     <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ทำสิ่งต่างๆ ได้มากขึ้นด้วยแถบงาน"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"แสดงแถบงานเสมอ"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"หากต้องการให้แถบงานแสดงที่ด้านล่างหน้าจออยู่เสมอ ให้แตะตัวแบ่งค้างไว้"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"แตะปุ่มดำเนินการค้างไว้เพื่อค้นหาสิ่งที่อยู่บนหน้าจอ"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ผลิตภัณฑ์นี้ใช้ส่วนที่เลือกของหน้าจอเพื่อค้นหา เป็นไปตาม<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>นโยบายความเป็นส่วนตัว<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>และ<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ข้อกําหนดในการให้บริการ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>ของ Google"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"แตะปุ่มดำเนินการค้างไว้เพื่อค้นหาสิ่งที่อยู่บนหน้าจอ"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ผลิตภัณฑ์นี้ใช้ส่วนที่เลือกของหน้าจอเพื่อค้นหา เป็นไปตาม<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>นโยบายความเป็นส่วนตัว<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>และ<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ข้อกําหนดในการให้บริการ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>ของ Google"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"เสร็จ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"หน้าแรก"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"การเพิ่มแอปไปยังเดสก์ท็อป"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ยกเลิก"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 5fbc57b..d97706a 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Mas maraming magawa gamit ang Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Palaging ipakita ang Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para palaging ipakita ang Taskbar sa ibaba ng iyong screen, pindutin nang matagal ang divider"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Pindutin nang matagal ang action key para hanapin kung ano ang nasa iyong screen"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ginagamit ng produktong ito ang piniling bahagi ng iyong screen para maghanap. Nalalapat ang <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Patakaran sa Privacy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> at <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Mga Tuntunin ng Serbisyo<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ng Google."</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Pindutin nang matagal ang action key para hanapin kung ano ang nasa iyong screen"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ginagamit ng produktong ito ang piniling bahagi ng iyong screen para maghanap. Nalalapat ang <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Patakaran sa Privacy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> at <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Mga Tuntunin ng Serbisyo<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ng Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Isara"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tapos na"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Idinaragdag ang app sa Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Kanselahin"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index a10d0e3..1d73f8f 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Görev çubuğuyla daha fazla şey yapın"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Görev çubuğunu sabitleyin"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ayırıcıya dokunup basılı tuttuğunuzda görev çubuğu ekranın alt kısmına sabitlenir"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekranınızda bulunan içerikleri aramak için eylem tuşuna dokunup basılı tutun"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu ürün, ekranınızın seçilen bölümünü kullanarak arama yapar. Google\'ın <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Gizlilik Politikası<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ve <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Hizmet Şartları<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> geçerlidir."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Kapat"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Bitti"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ana ekran"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Uygulama Masaüstü\'ne ekleniyor"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"İptal"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 5e19342..2ad4437 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Більше можливостей завдяки панелі завдань"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Завжди показувати панель завдань"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Щоб завжди показувати панель завдань унизу екрана, натисніть і втримуйте роздільник"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Для пошуку інформації, що відображається на екрані, натисніть і втримуйте клавішу дії"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Цей продукт використовує для пошуку вибрану частину екрана. Застосовуються <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Політика конфіденційності<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> та <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Загальні положення й умови<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Головний екран"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Встановлення додатка на комп’ютер"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Скасувати"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 7b14045..dbb226f6 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,8 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ٹاسک بار سے بہت کچھ کریں"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ہمیشہ ٹاسک بار دکھائیں"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ٹاسک بار کو ہمیشہ اپنی اسکرین کے نیچے دکھانے کے لیے، ڈیوائیڈر کو ٹچ کریں اور دبائے رکھیں"</string>
-    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"آپ کی اسکرین پر جو کچھ ہے اسے تلاش کرنے کے لیے ایکشن کلید کو ٹچ کریں اور دبائے رکھیں"</string>
-    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏یہ پروڈکٹ تلاش کرنے کے لیے آپ کی اسکرین کا منتخب حصہ استعمال کرتا ہے۔ Google کی <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>رازداری کی پالیسی<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> اور <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>سروس کی شرائط<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> لاگو ہوتی ہیں۔"</string>
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"آپ کی اسکرین پر جو کچھ ہے اسے تلاش کرنے کے لیے ایکشن کلید کو ٹچ کریں اور دبائے رکھیں"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"‏یہ پروڈکٹ تلاش کرنے کے لیے آپ کی اسکرین کا منتخب حصہ استعمال کرتا ہے۔ Google کی <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>رازداری کی پالیسی<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> اور <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>سروس کی شرائط<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> لاگو ہوتی ہیں۔"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ہو گیا"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ہوم"</string>
@@ -139,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"ڈیسک ٹاپ پر ایپ شامل کرنا"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"منسوخ کریں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index efbb6a3..75ac23e 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Vazifalar panelidan maksimal darajada foydalaning"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vazifalar paneli doim chiqarilsin"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Vazifalar panelini ekranning pastki qismida doim chiqib turishi uchun ajratkichni bosib turing"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekrandagi element haqida maʼlumotni topish uchun amal tugmasini bosib turing"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu mahsulot qidirish uchun ekranning tanlangan qismidan foydalanadi. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>maxfiylik siyosati<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> va <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>xizmat shartlari<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> tatbiq qilinadi."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tayyor"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Bosh ekran"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Ilova kompyuterga qoʻshilmoqda"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Bekor qilish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 8d35279..55b7585 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Máy tính"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
@@ -93,7 +92,7 @@
     <string name="allset_button_hint" msgid="2395219947744706291">"Nhấn vào nút màn hình chính để chuyển đến màn hình chính"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Bạn có thể bắt đầu sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"thiết bị"</string>
-    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Chế độ cài đặt di chuyển trên hệ thống"</annotation></string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Cài đặt cách thao tác trên hệ thống"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
     <string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Làm nhiều việc hơn qua Thanh tác vụ"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Luôn hiện Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Để luôn hiện Taskbar ở cuối màn hình, hãy nhấn và giữ đường phân chia"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Chạm và giữ phím hành động để tìm nội dung trên màn hình của bạn"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Sản phẩm này dùng phần được chọn trên màn hình để tìm kiếm. Có áp dụng <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Chính sách quyền riêng tư<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> và <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Điều khoản dịch vụ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> của Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Xong"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Màn hình chính"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Đang thêm ứng dụng vào máy tính"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Huỷ"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b567c66..727f3e7 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -96,7 +95,7 @@
     <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_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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"体验任务栏的更多功能"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"始终显示任务栏"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"若要始终在屏幕底部显示任务栏,请轻触并按住分隔线"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"轻触并按住操作键,即可根据屏幕上的内容进行搜索"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"此产品会根据屏幕上的所选内容进行搜索。Google 的<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>《隐私权政策》<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>和<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>《服务条款》<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>适用。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"主屏幕"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"将应用添加到桌面"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index b314def..519a7b2 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"工作列助你事半功倍"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要持續在畫面底部顯示工作列,請按住分隔線"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"此產品使用螢幕的特定部分進行搜尋。須受 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>私隱權政策<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>服務條款<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>》約束。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"住宅"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"正在新增應用程式至桌面"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 0864c55..a8cefce 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,8 +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>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <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>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"充分發揮工作列的功用"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要一律在畫面底部顯示工作列,請按住分隔線"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"這項產品會搜尋你在畫面上選取的內容 (適用 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>隱私權政策<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>服務條款<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>》)。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"主畫面"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"新增應用程式至桌面"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index e1c1f3a..9028210 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -21,8 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
-    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
-    <skip />
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
@@ -118,10 +117,8 @@
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Yenza okwengeziwe nge-Taskbar"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Bonisa njalo i-Taskbar"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ukuze ubonise njalo i-Taskbar phansi kwesikrini sakho, thinta bese ubamba isihlukanisi"</string>
-    <!-- no translation found for taskbar_edu_circle_to_search_title (4322780398403949508) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_circle_to_search_disclosure (5841648785867787221) -->
-    <skip />
+    <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Thinta uphinde ubambe inkinobho yokufinyelela ukuze useshe lokho okusesikrinini sakho"</string>
+    <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Lo mkhiqizo usebenzisa ingxenye ekhethiwe yesikrini sakho ukusesha. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Inqubomgomo Yobumfihlo<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ye-Google kanye <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Nemigomo Yesevisi<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ziyasebenza."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kwenziwe"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ikhaya"</string>
@@ -141,6 +138,7 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
     <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
+    <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Yengeza i-app ku-Deskithophu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Khansela"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 1b5b0ee..14a916f 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -31,6 +31,7 @@
     <color name="taskbar_nav_icon_dark_color_on_home">#99000000</color>
     <color name="taskbar_stashed_handle_light_color">#EBffffff</color>
     <color name="taskbar_stashed_handle_dark_color">#99000000</color>
+    <color name="taskbar_running_app_indicator_color">#646464</color>
 
     <!-- Floating rotation button -->
     <color name="floating_rotation_button_light_color">#ffffff</color>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 28cdb99..fd12210 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -17,8 +17,7 @@
     <string name="overscroll_plugin_factory_class" translatable="false" />
     <string name="task_overlay_factory_class" translatable="false"/>
 
-    <!-- Activities which block home gesture -->
-    <string-array name="gesture_blocking_activities" translatable="false">
+    <string-array name="back_gesture_blocking_activities" translatable="false">
         <item>com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity</item>
     </string-array>
 
@@ -35,6 +34,7 @@
     <string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
     <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="nav_handle_long_press_handler_class" translatable="false"></string>
     <string name="assist_utils_class" translatable="false"></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 69e07f2..7f09b6e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -177,6 +177,8 @@
     <dimen name="gesture_tutorial_menu_done_button_top_spacing">0dp</dimen>
     <dimen name="gesture_tutorial_menu_back_shape_bottom_margin">0dp</dimen>
     <dimen name="gesture_tutorial_menu_done_button_spacing">72dp</dimen>
+    <dimen name="gesture_tutorial_done_button_bottom_margin">40dp</dimen>
+    <dimen name="gesture_tutorial_done_button_end_margin">24dp</dimen>
 
     <!-- Gesture Tutorial mock conversations -->
     <dimen name="gesture_tutorial_message_icon_size">44dp</dimen>
@@ -353,6 +355,9 @@
     <dimen name="taskbar_back_button_suw_start_margin">48dp</dimen>
     <dimen name="taskbar_back_button_suw_bottom_margin">1dp</dimen>
     <dimen name="taskbar_back_button_suw_height">72dp</dimen>
+    <dimen name="taskbar_running_app_indicator_height">4dp</dimen>
+    <dimen name="taskbar_running_app_indicator_width">14dp</dimen>
+    <dimen name="taskbar_running_app_indicator_top_margin">2dp</dimen>
 
     <!-- Transient taskbar -->
     <dimen name="transient_taskbar_padding">12dp</dimen>
@@ -403,7 +408,7 @@
     <dimen name="taskbar_edu_features_tooltip_width_with_one_feature">412dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_two_features">428dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_three_features">624dp</dimen>
-    <dimen name="taskbar_edu_circle_to_search_subtitle_text_size">12sp</dimen>
+    <dimen name="taskbar_edu_search_subtitle_text_size">12sp</dimen>
 
     <!--- Taskbar Pinning -->
     <dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
@@ -420,18 +425,26 @@
     <dimen name="bubblebar_stashed_handle_width">55dp</dimen>
     <dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
     <dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
-    <dimen name="bubblebar_pointer_size">8dp</dimen>
+    <!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
+    background appropriately when close to the rounded corner -->
+    <dimen name="bubblebar_pointer_visible_size">9dp</dimen>
+    <dimen name="bubblebar_pointer_width">12dp</dimen>
+    <dimen name="bubblebar_pointer_height">10dp</dimen>
+    <dimen name="bubblebar_pointer_radius">2dp</dimen>
     <!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
     <dimen name="bubblebar_size_with_pointer">80dp</dimen>
     <dimen name="bubblebar_elevation">1dp</dimen>
     <dimen name="bubblebar_drag_elevation">2dp</dimen>
     <dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
 
-    <dimen name="bubblebar_icon_size">50dp</dimen>
+    <dimen name="bubblebar_icon_size_small">32dp</dimen>
+    <dimen name="bubblebar_icon_size">36dp</dimen>
     <dimen name="bubblebar_badge_size">24dp</dimen>
     <dimen name="bubblebar_icon_overlap">12dp</dimen>
-    <dimen name="bubblebar_overflow_inset">24dp</dimen>
-    <dimen name="bubblebar_icon_spacing">3dp</dimen>
+    <dimen name="bubblebar_overflow_inset">16dp</dimen>
+    <dimen name="bubblebar_icon_spacing">6dp</dimen>
+    <dimen name="bubblebar_icon_spacing_large">8dp</dimen>
+    <dimen name="bubblebar_expanded_icon_spacing">12dp</dimen>
     <dimen name="bubblebar_icon_elevation">1dp</dimen>
 
     <!-- Bubble bar dismiss view -->
@@ -445,6 +458,11 @@
 
     <!-- Bubble bar drop target -->
     <dimen name="bubblebar_drop_target_corner_radius">36dp</dimen>
+    <dimen name="bubble_expanded_view_drop_target_default_width">412dp</dimen>
+    <dimen name="bubble_expanded_view_drop_target_default_height">600dp</dimen>
+    <dimen name="bubble_expanded_view_drop_target_corner_radius">28dp</dimen>
+    <dimen name="bubble_expanded_view_drop_target_padding">24dp</dimen>
+    <dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
 
     <!-- Launcher splash screen -->
     <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 71855eb..278c66a 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -275,10 +275,10 @@
     <string name="taskbar_edu_pinning_title">Always show the Taskbar</string>
     <!-- Text in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 150] -->
     <string name="taskbar_edu_pinning_standalone">To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider</string>
-    <!-- Title in dialog that shows a user how to invoke the Circle to Search feature. [CHAR_LIMIT 150] -->
-    <string name="taskbar_edu_circle_to_search_title">Touch &amp; hold the action key to search what\'s on your screen</string>
+    <!-- Title in dialog that shows a user how to invoke the Search feature. [CHAR_LIMIT 150] -->
+    <string name="taskbar_search_edu_title">Touch &amp; hold the action key to search what\'s on your screen</string>
     <!-- Message showed to user to disclose privacy information they need to accept in order to access the app. [CHAR LIMIT=200]-->
-    <string name="taskbar_edu_circle_to_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link">&lt;a href=\"%1$s\"&gt;</xliff:g>Privacy Policy<xliff:g id="end_privacy_link">&lt;/a&gt;</xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link">&lt;a href=\"%2$s\"&gt;</xliff:g>Terms of Service<xliff:g id="end_tos_link">&lt;/a&gt;</xliff:g> apply.</string>
+    <string name="taskbar_edu_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link">&lt;a href=\"%1$s\"&gt;</xliff:g>Privacy Policy<xliff:g id="end_privacy_link">&lt;/a&gt;</xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link">&lt;a href=\"%2$s\"&gt;</xliff:g>Terms of Service<xliff:g id="end_tos_link">&lt;/a&gt;</xliff:g> apply.</string>
     <!-- Text on button to exit a tutorial [CHAR_LIMIT=16] -->
     <string name="taskbar_edu_close">Close</string>
     <!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
@@ -324,6 +324,12 @@
             other{Show # more apps.}
         }</string>
 
+    <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
+    <string name="quick_switch_desktop">{count, plural,
+            =1{Show # desktop app.}
+            other{Show # desktop apps.}
+        }</string>
+
     <!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
     <string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
 
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 16fb6d2..952505a 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -169,17 +169,17 @@
 
     <style name="TextAppearance.GestureTutorial.MainTitle.Home"
         parent="TextAppearance.GestureTutorial.MainTitle">
-        <item name="android:textColor">?attr/onSurfaceHome</item>
+        <item name="android:textColor">?attr/secondaryHome</item>
     </style>
 
     <style name="TextAppearance.GestureTutorial.MainTitle.Back"
         parent="TextAppearance.GestureTutorial.MainTitle">
-        <item name="android:textColor">?attr/onSurfaceBack</item>
+        <item name="android:textColor">?attr/secondaryBack</item>
     </style>
 
     <style name="TextAppearance.GestureTutorial.MainTitle.Overview"
         parent="TextAppearance.GestureTutorial.MainTitle">
-        <item name="android:textColor">?attr/onSurfaceOverview</item>
+        <item name="android:textColor">?attr/secondaryOverview</item>
     </style>
 
     <style name="TextAppearance.GestureTutorial.MainTitle.Success.Home"
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 0697f47..72aaa90 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -58,6 +58,7 @@
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
 import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
@@ -1881,7 +1882,7 @@
 
             return new ContainerAnimationRunner(
                     new ActivityTransitionAnimator.AnimationDelegate(
-                            controller, callback, listener));
+                            MAIN_EXECUTOR, controller, callback, listener));
         }
 
         /**
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 694475a..84c2ed2 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -28,14 +28,15 @@
 import android.text.TextPaint;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.ColorInt;
 import androidx.core.content.ContextCompat;
 
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.FloatingHeaderRow;
 import com.android.launcher3.allapps.FloatingHeaderView;
-import com.android.launcher3.util.Themes;
 
 /**
  * A view which shows a horizontal divider
@@ -54,6 +55,7 @@
 
     private final @ColorInt int mStrokeColor;
     private final @ColorInt int mAllAppsLabelTextColor;
+    private final AccessibilityManager mAccessibilityManager;
 
     private Layout mAllAppsLabelLayout;
     private boolean mShowAllAppsLabel;
@@ -87,7 +89,8 @@
         mAllAppsLabelTextColor = ContextCompat.getColor(context,
                 R.color.material_color_on_surface_variant);
 
-        mShowAllAppsLabel = !ALL_APPS_VISITED_COUNT.hasReachedMax(context);
+        mAccessibilityManager = AccessibilityManager.getInstance(context);
+        setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(context));
     }
 
     public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
@@ -99,6 +102,9 @@
 
     /** {@code true} if all apps label should be shown in place of divider. */
     public void setShowAllAppsLabel(boolean showAllAppsLabel) {
+        if (mAccessibilityManager.isEnabled() && !Utilities.isRunningInTestHarness()) {
+            showAllAppsLabel = true;
+        }
         if (showAllAppsLabel != mShowAllAppsLabel) {
             mShowAllAppsLabel = showAllAppsLabel;
             updateDividerType();
@@ -148,6 +154,7 @@
             mDividerType = dividerType;
             int topPadding;
             int bottomPadding;
+            setContentDescription(null);
             switch (dividerType) {
                 case LINE:
                     topPadding = 0;
@@ -161,6 +168,7 @@
                     bottomPadding = getResources()
                             .getDimensionPixelSize(R.dimen.all_apps_label_bottom_padding);
                     mPaint.setColor(mAllAppsLabelTextColor);
+                    setContentDescription(mAllAppsLabelLayout.getText());
                     break;
                 case NONE:
                 default:
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 70e01f5..a16031d 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -286,7 +286,7 @@
     }
 
     public void dump(String prefix, PrintWriter writer) {
-        writer.println(prefix + this.getClass().getSimpleName());
+        writer.println(prefix + "PredictionRowView");
         writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled);
         writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused);
         writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow);
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 1c5a75d..de974ec 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -29,6 +29,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.ComponentName;
+import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
 import android.view.ViewGroup;
@@ -80,6 +81,7 @@
         SystemShortcut.Factory<QuickstepLauncher>, DeviceProfile.OnDeviceProfileChangeListener,
         DragSource, ViewGroup.OnHierarchyChangeListener {
 
+    private static final String TAG = "HotseatPredictionController";
     private static final int FLAG_UPDATE_PAUSED = 1 << 0;
     private static final int FLAG_DRAG_IN_PROGRESS = 1 << 1;
     private static final int FLAG_FILL_IN_PROGRESS = 1 << 2;
@@ -292,6 +294,16 @@
     }
 
     /**
+     * Ensures that if the flag FLAG_UPDATE_PAUSED is active we set it to false.
+     */
+    public void verifyUIUpdateNotPaused() {
+        if ((mPauseFlags & FLAG_UPDATE_PAUSED) != 0) {
+            setPauseUIUpdate(false);
+            Log.e(TAG, "FLAG_UPDATE_PAUSED should not be set to true (see b/339700174)");
+        }
+    }
+
+    /**
      * Sets or updates the predicted items
      */
     public void setPredictedItems(FixedContainerItems items) {
@@ -521,7 +533,7 @@
     }
 
     public void dump(String prefix, PrintWriter writer) {
-        writer.println(prefix + this.getClass().getSimpleName());
+        writer.println(prefix + "HotseatPredictionController");
         writer.println(prefix + "\tFlags: " + getStateString(mPauseFlags));
         writer.println(prefix + "\tmHotSeatItemsCount: " + mHotSeatItemsCount);
         writer.println(prefix + "\tmPredictedItems: " + mPredictedItems);
diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
index 2fcbe4e..d604742 100644
--- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
@@ -15,8 +15,8 @@
  */
 package com.android.launcher3.model;
 
-import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
 
@@ -32,6 +32,7 @@
 
 import com.android.launcher3.ConstantItem;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
@@ -47,7 +48,7 @@
 /**
  * Task to update model as a result of predicted apps update
  */
-public class PredictionUpdateTask extends BaseModelUpdateTask {
+public class PredictionUpdateTask implements ModelUpdateTask {
 
     public static final ConstantItem<Boolean> LAST_PREDICTION_ENABLED =
             nonRestorableItem("last_prediction_enabled_state", true, ENCRYPTED);
@@ -61,8 +62,9 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
+        LauncherAppState app = taskController.getApp();
         Context context = app.getContext();
 
         // TODO: remove this
@@ -119,7 +121,7 @@
 
         FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId, items);
         dataModel.extraItems.put(fci.containerId, fci);
-        bindExtraContainerItems(fci);
+        taskController.bindExtraContainerItems(fci);
         usersForChangedShortcuts.forEach(
                 u -> dataModel.updateShortcutPinnedState(app.getContext(), u));
 
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index bc35125..8b5ed7c 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -70,8 +70,10 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PersistedItemArray;
 import com.android.quickstep.logging.SettingsChangeLogger;
 import com.android.quickstep.logging.StatsLogCompatManager;
@@ -149,7 +151,8 @@
         // TODO: Implement caching and preloading
 
         WorkspaceItemFactory factory =
-                new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, numColumns, state.containerId);
+                new WorkspaceItemFactory(mApp, ums, mPmHelper, pinnedShortcuts, numColumns,
+                        state.containerId);
         FixedContainerItems fci = new FixedContainerItems(state.containerId,
                 state.storage.read(mApp.getContext(), factory, ums.allUsers::get));
         if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
@@ -325,8 +328,12 @@
         super.destroy();
         mActive = false;
         StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
-        if (mIsPrimaryInstance) {
-            mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+        if (mIsPrimaryInstance && mStatsManager != null) {
+            try {
+                mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Failed to unregister snapshot logging callback with StatsManager", e);
+            }
         }
         destroyPredictors();
     }
@@ -525,6 +532,7 @@
 
         private final LauncherAppState mAppState;
         private final UserManagerState mUMS;
+        private final PackageManagerHelper mPmHelper;
         private final Map<ShortcutKey, ShortcutInfo> mPinnedShortcuts;
         private final int mMaxCount;
         private final int mContainer;
@@ -532,9 +540,11 @@
         private int mReadCount = 0;
 
         protected WorkspaceItemFactory(LauncherAppState appState, UserManagerState ums,
-                Map<ShortcutKey, ShortcutInfo> pinnedShortcuts, int maxCount, int container) {
+                PackageManagerHelper pmHelper, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts,
+                int maxCount, int container) {
             mAppState = appState;
             mUMS = ums;
+            mPmHelper = pmHelper;
             mPinnedShortcuts = pinnedShortcuts;
             mMaxCount = maxCount;
             mContainer = container;
@@ -557,6 +567,8 @@
                     AppInfo info = new AppInfo(
                             lai,
                             UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user),
+                            ApiWrapper.INSTANCE.get(mAppState.getContext()),
+                            mPmHelper,
                             mUMS.isUserQuiet(user));
                     info.container = mContainer;
                     mAppState.getIconCache().getTitleAndIcon(info, lai, false);
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index c345d6e..a7c9652 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -32,7 +32,6 @@
 import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -48,9 +47,10 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.RemoteActionShortcut;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.BgObjectWithLooper;
+import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.views.ActivityContext;
 
@@ -61,7 +61,7 @@
 /**
  * Data model for digital wellbeing status of apps.
  */
-public final class WellbeingModel extends BgObjectWithLooper {
+public final class WellbeingModel implements SafeCloseable {
     private static final String TAG = "WellbeingModel";
     private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
     private static final boolean DEBUG = false;
@@ -81,8 +81,12 @@
     private final Context mContext;
     private final String mWellbeingProviderPkg;
 
-    private Handler mWorkerHandler;
-    private ContentObserver mContentObserver;
+    private final Handler mWorkerHandler;
+    private final ContentObserver mContentObserver;
+    private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
+            new SimpleBroadcastReceiver(t -> restartObserver());
+    private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
+            new SimpleBroadcastReceiver(this::onAppPackageChanged);
 
     private final Object mModelLock = new Object();
     // Maps the action Id to the corresponding RemoteAction
@@ -94,16 +98,23 @@
     private WellbeingModel(final Context context) {
         mContext = context;
         mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
-        initializeInBackground("WellbeingHandler");
+        mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
+                ? Executors.UI_HELPER_EXECUTOR.getLooper()
+                : Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
+
+        mContentObserver = new ContentObserver(mWorkerHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                updateAllPackages();
+            }
+        };
+        mWorkerHandler.post(this::initializeInBackground);
     }
 
-    @Override
-    protected void onInitialized(Looper looper) {
-        mWorkerHandler = new Handler(looper);
-        mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
+    private void initializeInBackground() {
         if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
             mContext.registerReceiver(
-                    new SimpleBroadcastReceiver(t -> restartObserver()),
+                    mWellbeingAppChangeReceiver,
                     getPackageFilter(mWellbeingProviderPkg,
                             Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
                             Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
@@ -113,17 +124,21 @@
             IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
             filter.addDataScheme("package");
-            mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
-                    filter, null, mWorkerHandler);
+            mContext.registerReceiver(mAppAddRemoveReceiver, filter, null, mWorkerHandler);
 
             restartObserver();
         }
     }
 
-    @WorkerThread
-    private void onWellbeingUriChanged(Uri uri) {
-        Preconditions.assertNonUiThread();
-        updateAllPackages();
+    @Override
+    public void close() {
+        if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
+            mWorkerHandler.post(() -> {
+                mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
+                mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
+                mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+            });
+        }
     }
 
     public void setInTest(boolean inTest) {
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index f4cbf17..39f2c00 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -24,7 +24,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
 import com.android.launcher3.model.data.ItemInfo;
@@ -41,7 +41,7 @@
 import java.util.stream.Collectors;
 
 /** Task to update model as a result of predicted widgets update */
-public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask {
+public final class WidgetsPredictionUpdateTask implements ModelUpdateTask {
     private final PredictorState mPredictorState;
     private final List<AppTarget> mTargets;
 
@@ -58,8 +58,8 @@
      * workspace.
      */
     @Override
-    public void execute(@NonNull final LauncherAppState appState,
-            @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
         Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map(
                 widget -> new ComponentKey(widget.providerName, widget.user)).collect(
                 Collectors.toSet());
@@ -98,7 +98,7 @@
 
         List<ItemInfo> items;
         if (enableCategorizedWidgetSuggestions()) {
-            Context context = appState.getContext();
+            Context context = taskController.getApp().getContext();
             WidgetRecommendationCategoryProvider categoryProvider =
                     WidgetRecommendationCategoryProvider.newInstance(context);
             items = servicePredictedItems.stream()
@@ -115,7 +115,7 @@
                 new FixedContainerItems(mPredictorState.containerId, items);
 
         dataModel.extraItems.put(mPredictorState.containerId, fixedContainerItems);
-        bindExtraContainerItems(fixedContainerItems);
+        taskController.bindExtraContainerItems(fixedContainerItems);
 
         // Don't store widgets prediction to disk because it is not used frequently.
     }
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
index 184ea71..fe9ade9 100644
--- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -25,7 +25,7 @@
 /** {@link SystemShortcut.Factory} implementation to create workspace split shortcuts */
 public interface QuickstepSystemShortcut {
 
-    String TAG = QuickstepSystemShortcut.class.getSimpleName();
+    String TAG = "QuickstepSystemShortcut";
 
     static SystemShortcut.Factory<QuickstepLauncher> getSplitSelectShortcutByPosition(
             SplitPositionOption position) {
diff --git a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
index 2b6f77f..c94edce 100644
--- a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
+++ b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
@@ -45,7 +45,7 @@
 ) : SystemShortcut<T>(iconResId, labelResId, target, itemInfo, originalView) where
 T : Context?,
 T : ActivityContext? {
-    private val TAG = SystemShortcut::class.java.simpleName
+    private val TAG = "SplitShortcut"
 
     // Initiate splitscreen from the Home screen or Home All Apps
     protected val splitSelectSource: SplitSelectSource?
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 882682d..747612d 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -182,7 +182,7 @@
     }
 
     public void dump(String prefix, PrintWriter writer) {
-        writer.println(prefix + this.getClass().getSimpleName());
+        writer.println(prefix + "DepthController");
         writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
         writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
         writer.println(prefix + "\tmSurface=" + mSurface);
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index c0dacf1..9eabb55 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -19,6 +19,7 @@
 
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.os.Debug;
 import android.os.SystemProperties;
@@ -31,11 +32,15 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.views.DesktopAppSelectView;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Controls the visibility of the workspace and the resumed / paused state when desktop mode
  * is enabled.
@@ -47,6 +52,7 @@
     private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_stashing", false);
     private final Launcher mLauncher;
+    private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
 
     private int mVisibleDesktopTasksCount;
     private boolean mInOverviewState;
@@ -126,6 +132,16 @@
         return mVisibleDesktopTasksCount;
     }
 
+    /** Registers a listener for Desktop Mode visibility updates. */
+    public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
+        mDesktopVisibilityListeners.add(listener);
+    }
+
+    /** Removes a previously registered Desktop Mode visibility listener. */
+    public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
+        mDesktopVisibilityListeners.remove(listener);
+    }
+
     /**
      * Sets the number of desktop windows that are visible and updates launcher visibility based on
      * it.
@@ -139,9 +155,15 @@
         if (visibleTasksCount != mVisibleDesktopTasksCount) {
             final boolean wasVisible = mVisibleDesktopTasksCount > 0;
             final boolean isVisible = visibleTasksCount > 0;
+            final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
             mVisibleDesktopTasksCount = visibleTasksCount;
+            final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+            if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+                notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+            }
 
-            if (wasVisible != isVisible) {
+            if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
+                // TODO: b/333533253 - Remove after flag rollout
                 if (mVisibleDesktopTasksCount > 0) {
                     setLauncherViewsVisibility(View.INVISIBLE);
                     if (!mInOverviewState) {
@@ -177,11 +199,22 @@
                     + " currentValue=" + mInOverviewState);
         }
         if (overviewStateEnabled != mInOverviewState) {
+            final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
             mInOverviewState = overviewStateEnabled;
+            final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+            if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+                notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+            }
+
+            if (enableDesktopWindowingWallpaperActivity()) {
+                return;
+            }
+            // TODO: b/333533253 - Clean up after flag rollout
+
             if (mInOverviewState) {
                 setLauncherViewsVisibility(View.VISIBLE);
                 markLauncherResumed();
-            } else if (areDesktopTasksVisible() && !mGestureInProgress) {
+            } else if (areDesktopTasksVisibleNow && !mGestureInProgress) {
                 // Switching out of overview state and gesture finished.
                 // If desktop tasks are still visible, hide launcher again.
                 setLauncherViewsVisibility(View.INVISIBLE);
@@ -190,6 +223,19 @@
         }
     }
 
+    private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
+        }
+        for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
+            listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
+        }
+        DisplayController.handleInfoChangeForDesktopMode(mLauncher);
+    }
+
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setBackgroundStateEnabled(boolean backgroundStateEnabled) {
         if (DEBUG) {
             Log.d(TAG, "setBackgroundStateEnabled: enabled=" + backgroundStateEnabled
@@ -210,6 +256,8 @@
 
     /**
      * Whether recents gesture is currently in progress.
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public boolean isRecentsGestureInProgress() {
         return mGestureInProgress;
@@ -217,6 +265,8 @@
 
     /**
      * Notify controller that recents gesture has started.
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public void setRecentsGestureStart() {
         if (DEBUG) {
@@ -228,6 +278,8 @@
     /**
      * Notify controller that recents gesture finished with the given
      * {@link com.android.quickstep.GestureState.GestureEndTarget}
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public void setRecentsGestureEnd(@Nullable GestureState.GestureEndTarget endTarget) {
         if (DEBUG) {
@@ -241,6 +293,9 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setRecentsGestureInProgress(boolean gestureInProgress) {
         if (gestureInProgress != mGestureInProgress) {
             mGestureInProgress = gestureInProgress;
@@ -256,7 +311,13 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setLauncherViewsVisibility(int visibility) {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
                     + Debug.getCaller());
@@ -275,7 +336,13 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void markLauncherPaused() {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "markLauncherPaused " + Debug.getCaller());
         }
@@ -286,7 +353,13 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void markLauncherResumed() {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "markLauncherResumed " + Debug.getCaller());
         }
@@ -323,4 +396,14 @@
         mSelectAppToast.hide();
         mSelectAppToast = null;
     }
+
+    /** A listener for when the user enters/exits Desktop Mode. */
+    public interface DesktopVisibilityListener {
+        /**
+         * Callback for when the user enters or exits Desktop Mode
+         *
+         * @param visible whether Desktop Mode is now visible
+         */
+        void onDesktopVisibilityChanged(boolean visible);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
deleted file mode 100644
index 3635827..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_NOTIFICATIONS;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_QUICK_SETTINGS;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo.Config;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
-
-/**
- * Controller for managing buttons and status icons in taskbar in a desktop environment.
- */
-public class DesktopNavbarButtonsViewController extends NavbarButtonsViewController {
-
-    private final TaskbarActivityContext mContext;
-    private final FrameLayout mNavButtonsView;
-    private final ViewGroup mNavButtonContainer;
-    private final ViewGroup mStartContextualContainer;
-    private final View mAllAppsButton;
-
-    private TaskbarControllers mControllers;
-
-    public DesktopNavbarButtonsViewController(TaskbarActivityContext context,
-            @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
-        super(context, navigationBarPanelContext, navButtonsView);
-        mContext = context;
-        mNavButtonsView = navButtonsView;
-        mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
-        mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
-        mAllAppsButton = LayoutInflater.from(context)
-                .inflate(R.layout.taskbar_all_apps_button, mStartContextualContainer, false);
-        mAllAppsButton.setOnClickListener(v -> mControllers.taskbarAllAppsController.toggle());
-    }
-
-    /**
-     * Initializes the controller
-     */
-    @Override
-    public void init(TaskbarControllers controllers) {
-        mControllers = controllers;
-        super.init(controllers);
-    }
-
-    @Override
-    protected void setupController() {
-        mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarHeight;
-
-        // Quick settings and notifications buttons
-        addButton(R.drawable.ic_sysbar_quick_settings, BUTTON_QUICK_SETTINGS,
-                mNavButtonContainer, mControllers.navButtonController,
-                R.id.quick_settings_button);
-        addButton(R.drawable.ic_sysbar_notifications, BUTTON_NOTIFICATIONS,
-                mNavButtonContainer, mControllers.navButtonController,
-                R.id.notifications_button);
-        // All apps button
-        mStartContextualContainer.addView(mAllAppsButton);
-    }
-
-    /** Cleans up on destroy */
-    @Override
-    public void onDestroy() { }
-
-    @Override
-    public void onConfigurationChanged(@Config int configChanges) { }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java
deleted file mode 100644
index acfbea3..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.util.SparseArray;
-
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.quickstep.RecentsModel;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Provides recent apps functionality specifically in a desktop environment.
- */
-public class DesktopTaskbarRecentAppsController extends TaskbarRecentAppsController {
-
-    private final TaskbarActivityContext mContext;
-    private ArrayList<ItemInfo> mRunningApps = new ArrayList<>();
-    private AppInfo[] mApps;
-
-    public DesktopTaskbarRecentAppsController(TaskbarActivityContext context) {
-        mContext = context;
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mApps = null;
-    }
-
-    @Override
-    protected void setApps(AppInfo[] apps) {
-        mApps = apps;
-    }
-
-    @Override
-    protected boolean isEnabled() {
-        return true;
-    }
-
-    /**
-     * Set mRunningApps to hold currently running applications using the list of currently running
-     * tasks. Filtering is also done to ignore applications that are already on the taskbar in the
-     * original hotseat.
-     */
-    @Override
-    protected void updateRunningApps(SparseArray<ItemInfo> hotseatItems) {
-        ArrayList<AppInfo> runningApps = getRunningAppsFromTasks();
-        ArrayList<ItemInfo> filteredRunningApps = new ArrayList<>();
-        for (AppInfo runningApp : runningApps) {
-            boolean shouldAddOnTaskbar = true;
-            for (int i = 0; i < hotseatItems.size(); i++) {
-                if (hotseatItems.keyAt(i) >= mControllers.taskbarActivityContext.getDeviceProfile()
-                        .numShownHotseatIcons) {
-                    break;
-                }
-                if (hotseatItems.valueAt(i).getTargetPackage()
-                        .equals(runningApp.getTargetPackage())) {
-                    shouldAddOnTaskbar = false;
-                    break;
-                }
-            }
-            if (shouldAddOnTaskbar) {
-                filteredRunningApps.add(new WorkspaceItemInfo(runningApp));
-            }
-        }
-        mRunningApps = filteredRunningApps;
-        mControllers.taskbarViewController.commitRunningAppsToUI();
-    }
-
-    /**
-     * Returns a copy of hotseatItems with the addition of currently running applications.
-     */
-    @Override
-    protected ItemInfo[] updateHotseatItemInfos(ItemInfo[] hotseatItemInfos) {
-        // hotseatItemInfos.length would be 0 if deviceProfile.numShownHotseatIcons is 0, so we
-        // don't want to show anything in the hotseat
-        if (hotseatItemInfos.length == 0) return hotseatItemInfos;
-
-        int runningAppsIndex = 0;
-        ItemInfo[] newHotseatItemsInfo = Arrays.copyOf(
-                hotseatItemInfos, hotseatItemInfos.length + mRunningApps.size());
-        for (int i = hotseatItemInfos.length; i < newHotseatItemsInfo.length; i++) {
-            newHotseatItemsInfo[i] = mRunningApps.get(runningAppsIndex);
-            runningAppsIndex++;
-        }
-        return newHotseatItemsInfo;
-    }
-
-
-    /**
-     * Returns a list of running applications from the list of currently running tasks.
-     */
-    private ArrayList<AppInfo> getRunningAppsFromTasks() {
-        ArrayList<ActivityManager.RunningTaskInfo> tasks =
-                RecentsModel.INSTANCE.get(mContext).getRunningTasks();
-        ArrayList<AppInfo> runningApps = new ArrayList<>();
-        // early return if apps is empty, since we would have no AppInfo to compare
-        if (mApps == null)  {
-            return runningApps;
-        }
-
-        Set<String> seenPackages = new HashSet<>();
-        for (ActivityManager.RunningTaskInfo taskInfo : tasks) {
-            if (taskInfo.realActivity == null) continue;
-
-            // If a different task for the same package has already been handled, skip this one
-            String taskPackage = taskInfo.realActivity.getPackageName();
-            if (seenPackages.contains(taskPackage)) continue;
-
-            // Otherwise, get the corresponding AppInfo and add it to the list
-            seenPackages.add(taskPackage);
-            AppInfo app = getAppInfo(taskInfo.realActivity);
-            if (app == null) continue;
-            runningApps.add(app);
-        }
-        return runningApps;
-    }
-
-    /**
-     * Retrieves the corresponding AppInfo for the activity.
-     */
-    private AppInfo getAppInfo(ComponentName activity) {
-        String packageName = activity.getPackageName();
-        for (AppInfo app : mApps) {
-            if (!packageName.equals(app.getTargetPackage())) {
-                continue;
-            }
-            return app;
-        }
-        return null;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
new file mode 100644
index 0000000..3649c4e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import android.util.Log
+import android.util.SparseArray
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.valueIterator
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import kotlin.collections.filterNotNull
+
+/**
+ * Shows running apps when in Desktop Mode.
+ *
+ * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
+ * recent-apps behaviour when outside of Desktop Mode.
+ *
+ * This class should only be used if
+ * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
+ */
+class DesktopTaskbarRunningAppsController(
+    private val recentsModel: RecentsModel,
+    // Pass a provider here instead of the actual DesktopVisibilityController instance since that
+    // instance might not be available when this constructor is called.
+    private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
+) : TaskbarRecentAppsController() {
+
+    private var apps: Array<AppInfo>? = null
+    private var allRunningDesktopAppInfos: List<AppInfo>? = null
+
+    private val desktopVisibilityController: DesktopVisibilityController?
+        get() = desktopVisibilityControllerProvider()
+
+    private val isInDesktopMode: Boolean
+        get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
+
+    override fun onDestroy() {
+        super.onDestroy()
+        apps = null
+    }
+
+    @VisibleForTesting
+    public override fun setApps(apps: Array<AppInfo>?) {
+        this.apps = apps
+    }
+
+    override fun isEnabled() = true
+
+    @VisibleForTesting
+    public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
+        if (!isInDesktopMode) {
+            Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
+            return hotseatItems
+        }
+        val newHotseatItemInfos =
+            hotseatItems
+                .filterNotNull()
+                // Ignore predicted apps - we show running apps instead
+                .filter { itemInfo -> !itemInfo.isPredictedItem }
+                .toMutableList()
+        val runningDesktopAppInfos =
+            allRunningDesktopAppInfos?.let {
+                getRunningDesktopAppInfosExceptHotseatApps(it, newHotseatItemInfos.toList())
+            }
+        if (runningDesktopAppInfos != null) {
+            newHotseatItemInfos.addAll(runningDesktopAppInfos)
+        }
+        return newHotseatItemInfos.toTypedArray()
+    }
+
+    override fun getRunningApps(): Set<String> {
+        if (!isInDesktopMode) {
+            return emptySet()
+        }
+        return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
+    }
+
+    @VisibleForTesting
+    public override fun updateRunningApps() {
+        if (!isInDesktopMode) {
+            Log.d(TAG, "updateRunningApps: not in Desktop Mode")
+            mControllers.taskbarViewController.commitRunningAppsToUI()
+            return
+        }
+        allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+        mControllers.taskbarViewController.commitRunningAppsToUI()
+    }
+
+    private fun getRunningDesktopAppInfosExceptHotseatApps(
+        allRunningDesktopAppInfos: List<AppInfo>,
+        hotseatItems: List<ItemInfo>
+    ): List<ItemInfo> {
+        val hotseatPackages = hotseatItems.map { it.targetPackage }
+        return allRunningDesktopAppInfos
+            .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
+            .map { WorkspaceItemInfo(it) }
+    }
+
+    private fun getRunningDesktopAppInfos(): List<AppInfo> {
+        return getAppInfosFromRunningTasks(
+            recentsModel.runningTasks
+                .filter { taskInfo: RunningTaskInfo ->
+                    taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+                }
+                .toList()
+        )
+    }
+
+    // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
+    private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
+        // Early return if apps is empty, since we then have no AppInfo to compare to
+        if (apps == null) {
+            return emptyList()
+        }
+        val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
+        return packageNames
+            .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
+            .filterNotNull()
+    }
+
+    private fun <E> SparseArray<E>.toList(): List<E> {
+        return valueIterator().asSequence().toList()
+    }
+
+    companion object {
+        private const val TAG = "TabletDesktopTaskbarRunningAppsController"
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
deleted file mode 100644
index 2dd610c4..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.quickstep.util.TISBindHelper;
-
-/**
- * A data source which integrates with a Launcher instance, used specifically for a
- * desktop environment.
- */
-public class DesktopTaskbarUIController extends TaskbarUIController {
-
-    private final QuickstepLauncher mLauncher;
-
-    public DesktopTaskbarUIController(QuickstepLauncher launcher) {
-        mLauncher = launcher;
-    }
-
-    @SuppressWarnings("MissingSuperCall") // TODO: Fix me
-    @Override
-    protected void init(TaskbarControllers taskbarControllers) {
-        super.init(taskbarControllers);
-        mLauncher.getHotseat().setIconsAlpha(0f);
-        mControllers.taskbarViewController.updateRunningApps();
-    }
-
-    @SuppressWarnings("MissingSuperCall") // TODO: Fix me
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mLauncher.getHotseat().setIconsAlpha(1f);
-    }
-
-    /** Disable taskbar stashing in desktop environment. */
-    @Override
-    public boolean supportsVisualStashing() {
-        return false;
-    }
-
-    @Nullable
-    @Override
-    protected TISBindHelper getTISBindHelper() {
-        return mLauncher.getTISBindHelper();
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index c0ecc61..06d9ee6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -133,4 +133,9 @@
     protected TISBindHelper getTISBindHelper() {
         return mRecentsActivity.getTISBindHelper();
     }
+
+    @Override
+    protected String getTaskbarUIControllerName() {
+        return "FallbackTaskbarUIController";
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 584106b..b213203 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -151,20 +151,10 @@
     private void processLoadedTasks(ArrayList<GroupTask> tasks) {
         // Only store MAX_TASK tasks, from most to least recent
         Collections.reverse(tasks);
-
-        // Hide all desktop tasks and show them on the hidden tile
-        int hiddenDesktopTasks = 0;
-        DesktopTask desktopTask = findDesktopTask(tasks);
-        if (desktopTask != null) {
-            hiddenDesktopTasks = desktopTask.tasks.size();
-            tasks = tasks.stream()
-                    .filter(t -> !(t instanceof DesktopTask))
-                    .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
-        }
         mTasks = tasks.stream()
                 .limit(MAX_TASKS)
                 .collect(Collectors.toList());
-        mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS) + hiddenDesktopTasks;
+        mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
     }
 
     private void processLoadedTasksOnDesktop(ArrayList<GroupTask> tasks) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 2d9e236..5d47212 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,11 +36,14 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.res.ResourcesCompat;
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.R;
@@ -48,6 +51,7 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 
 import java.util.HashMap;
@@ -92,6 +96,7 @@
     private HorizontalScrollView mScrollView;
     private ConstraintLayout mContent;
 
+    private int mTaskViewWidth;
     private int mTaskViewHeight;
     private int mSpacing;
     private int mOutlineRadius;
@@ -128,6 +133,8 @@
         mContent = findViewById(R.id.content);
 
         Resources resources = getResources();
+        mTaskViewWidth = resources.getDimensionPixelSize(
+                R.dimen.keyboard_quick_switch_taskview_width);
         mTaskViewHeight = resources.getDimensionPixelSize(
                 R.dimen.keyboard_quick_switch_taskview_height);
         mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
@@ -135,21 +142,18 @@
         mIsRtl = Utilities.isRtl(resources);
     }
 
-    @NonNull
     private KeyboardQuickSwitchTaskView createAndAddTaskView(
             int index,
-            int width,
             boolean isFinalView,
-            boolean updateTasks,
+            @LayoutRes int resId,
             @NonNull LayoutInflater layoutInflater,
-            @Nullable View previousView,
-            @NonNull List<GroupTask> groupTasks) {
+            @Nullable View previousView) {
         KeyboardQuickSwitchTaskView taskView = (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
-                R.layout.keyboard_quick_switch_taskview, mContent, false);
+                resId, mContent, false);
         taskView.setId(View.generateViewId());
         taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
 
-        LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
+        LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
         // Create a left-to-right ordering of views (or right-to-left in RTL locales)
         if (previousView != null) {
             lp.startToEnd = previousView.getId();
@@ -167,45 +171,11 @@
             lp.horizontalBias = 1f;
         }
 
-        GroupTask groupTask = groupTasks.get(index);
-        taskView.setThumbnails(
-                groupTask.task1,
-                groupTask.task2,
-                updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
-                updateTasks ? mViewCallbacks::updateIconInBackground : null);
-
         mContent.addView(taskView, lp);
+
         return taskView;
     }
 
-    private void createAndAddOverviewButton(
-            int width,
-            @NonNull LayoutInflater layoutInflater,
-            @Nullable View previousView,
-            @NonNull String overflowString) {
-        KeyboardQuickSwitchTaskView overviewButton =
-                (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
-                        R.layout.keyboard_quick_switch_overview, this, false);
-        overviewButton.setOnClickListener(v -> mViewCallbacks.launchTaskAt(MAX_TASKS));
-
-        overviewButton.<TextView>findViewById(R.id.text).setText(overflowString);
-
-        ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
-                width, mTaskViewHeight);
-        if (previousView == null) {
-            lp.startToStart = PARENT_ID;
-        } else {
-            lp.endToEnd = PARENT_ID;
-            lp.startToEnd = previousView.getId();
-        }
-        lp.topToTop = PARENT_ID;
-        lp.bottomToBottom = PARENT_ID;
-        lp.setMarginEnd(mSpacing);
-        lp.setMarginStart(mSpacing);
-
-        mContent.addView(overviewButton, lp);
-    }
-
     protected void applyLoadPlan(
             @NonNull Context context,
             @NonNull List<GroupTask> groupTasks,
@@ -215,32 +185,57 @@
             @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
         mViewCallbacks = viewCallbacks;
         Resources resources = context.getResources();
-        int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
-        View previousView = null;
+        Resources.Theme theme = context.getTheme();
 
+        View previousTaskView = null;
         LayoutInflater layoutInflater = LayoutInflater.from(context);
         int tasksToDisplay = Math.min(MAX_TASKS, groupTasks.size());
         for (int i = 0; i < tasksToDisplay; i++) {
-            previousView = createAndAddTaskView(
+            GroupTask groupTask = groupTasks.get(i);
+            KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
                     i,
-                    width,
                     /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
-                    updateTasks,
+                    groupTask instanceof DesktopTask
+                            ? R.layout.keyboard_quick_switch_textonly_taskview
+                            : R.layout.keyboard_quick_switch_taskview,
                     layoutInflater,
-                    previousView,
-                    groupTasks);
+                    previousTaskView);
+
+            if (groupTask instanceof DesktopTask desktopTask) {
+                HashMap<String, Integer> args = new HashMap<>();
+                args.put("count", desktopTask.tasks.size());
+
+                currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
+                        ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
+                currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+                        resources.getString(R.string.quick_switch_desktop),
+                        Locale.getDefault()).format(args));
+            } else {
+                currentTaskView.setThumbnails(
+                        groupTask.task1,
+                        groupTask.task2,
+                        updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+                        updateTasks ? mViewCallbacks::updateIconInBackground : null);
+            }
+            previousTaskView = currentTaskView;
         }
 
         if (numHiddenTasks > 0) {
             HashMap<String, Integer> args = new HashMap<>();
             args.put("count", numHiddenTasks);
-            createAndAddOverviewButton(
-                    width,
+
+            View overviewButton = createAndAddTaskView(
+                    MAX_TASKS,
+                    /* isFinalView= */ true,
+                    R.layout.keyboard_quick_switch_textonly_taskview,
                     layoutInflater,
-                    previousView,
-                    new MessageFormat(
-                            resources.getString(R.string.quick_switch_overflow),
-                            Locale.getDefault()).format(args));
+                    previousTaskView);
+
+            overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
+                    ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
+            overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+                    resources.getString(R.string.quick_switch_overflow),
+                    Locale.getDefault()).format(args));
         }
         mDisplayingRecentTasks = !groupTasks.isEmpty();
 
@@ -362,8 +357,9 @@
                                         OPEN_OUTLINE_INTERPOLATOR));
                     }
                 });
-                animateFocusMove(-1, currentFocusIndexOverride == -1
-                        ? Math.min(mContent.getChildCount(), 1) : currentFocusIndexOverride);
+                animateFocusMove(-1, Math.min(
+                        mContent.getChildCount() - 1,
+                        currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
                 displayedContent.setVisibility(VISIBLE);
                 setVisibility(VISIBLE);
                 requestFocus();
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 25a97d4..d6ee92f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.SlideInRemoteTransition;
 import com.android.systemui.shared.recents.model.Task;
@@ -157,7 +158,13 @@
                 AnimationUtils.loadInterpolator(
                         context, android.R.interpolator.fast_out_extra_slow_in)),
                 "SlideInTransition");
-        if (mOnDesktop) {
+        if (task instanceof DesktopTask) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+                            .showDesktopApps(
+                                    mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+                                    remoteTransition));
+        } else if (mOnDesktop) {
             UI_HELPER_EXECUTOR.execute(() ->
                     SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
                             .showDesktopApp(task.task1.key.id));
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 81f2c0f..4f02122 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,18 +16,14 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
 import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
 import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.TaskTransitionSpec;
-import android.view.WindowManagerGlobal;
 import android.window.RemoteTransition;
 
 import androidx.annotation.NonNull;
@@ -37,7 +33,6 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.logging.InstanceId;
@@ -139,7 +134,6 @@
         mLauncher.setTaskbarUIController(null);
         mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
         mHomeState.removeListener(mVisibilityChangeListener);
-        updateTaskTransitionSpec(true);
     }
 
     private void onInAppDisplayProgressChanged() {
@@ -218,9 +212,10 @@
 
         DesktopVisibilityController desktopController =
                 LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
-        final boolean onDesktop =
-                desktopController != null && desktopController.areDesktopTasksVisible();
-        if (onDesktop) {
+        if (!enableDesktopWindowingWallpaperActivity()
+                && desktopController != null
+                && desktopController.areDesktopTasksVisible()) {
+            // TODO: b/333533253 - Remove after flag rollout
             isVisible = false;
         }
 
@@ -277,26 +272,6 @@
     private void onStashedInAppChanged(DeviceProfile deviceProfile) {
         boolean taskbarStashedInApps = mControllers.taskbarStashController.isStashedInApp();
         deviceProfile.isTaskbarPresentInApps = !taskbarStashedInApps;
-        updateTaskTransitionSpec(taskbarStashedInApps);
-    }
-
-    private void updateTaskTransitionSpec(boolean taskbarIsHidden) {
-        try {
-            if (taskbarIsHidden) {
-                // Clear custom task transition settings when the taskbar is stashed
-                WindowManagerGlobal.getWindowManagerService().clearTaskTransitionSpec();
-            } else {
-                // Adjust task transition spec to account for taskbar being visible
-                WindowManagerGlobal.getWindowManagerService().setTaskTransitionSpec(
-                        new TaskTransitionSpec(
-                                mLauncher.getColor(R.color.taskbar_background)));
-            }
-        } catch (RemoteException e) {
-            // This shouldn't happen but if it does task animations won't look good until the
-            // taskbar stashing state is changed.
-            Log.e(TAG, "Failed to update task transition spec to account for new taskbar state",
-                    e);
-        }
     }
 
     /**
@@ -304,8 +279,8 @@
      */
     public void showEduOnAppLaunch() {
         if (!shouldShowEduOnAppLaunch()) {
-            // Called in case the edu finishes and circle to search edu is still pending
-            mControllers.taskbarEduTooltipController.maybeShowCircleToSearchEdu();
+            // Called in case the edu finishes and search edu is still pending
+            mControllers.taskbarEduTooltipController.maybeShowSearchEdu();
             return;
         }
 
@@ -471,4 +446,9 @@
 
         mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
     }
+
+    @Override
+    protected String getTaskbarUIControllerName() {
+        return "LauncherTaskbarUIController";
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 2c5aeb3..abb763a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -317,38 +317,28 @@
             mPropertyHolders.add(new StatePropertyHolder(
                     mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
                     flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
-
-            // Rotation button
-            RotationButton rotationButton = new RotationButtonImpl(
-                    addButton(mEndContextualContainer, R.id.rotate_suggestion,
-                            R.layout.taskbar_contextual_button));
-            rotationButton.hide();
-            mControllers.rotationButtonController.setRotationButton(rotationButton, null);
-        } else {
-            mFloatingRotationButton = new FloatingRotationButton(
-                    ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
-                    R.string.accessibility_rotate_button,
-                    R.layout.rotate_suggestion,
-                    R.id.rotate_suggestion,
-                    R.dimen.floating_rotation_button_min_margin,
-                    R.dimen.rounded_corner_content_padding,
-                    R.dimen.floating_rotation_button_taskbar_left_margin,
-                    R.dimen.floating_rotation_button_taskbar_bottom_margin,
-                    R.dimen.floating_rotation_button_diameter,
-                    R.dimen.key_button_ripple_max_width,
-                    R.bool.floating_rotation_button_position_left);
-            mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
-                    mRotationButtonListener);
-
-            if (!mIsImeRenderingNavButtons) {
-                View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
-                        mStartContextualContainer, mControllers.navButtonController, R.id.back);
-                imeDownButton.setRotation(Utilities.isRtl(resources) ? 90 : -90);
-                // Only show when IME is visible.
-                mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
-                        flags -> (flags & FLAG_IME_VISIBLE) != 0));
-            }
+        } else if (!mIsImeRenderingNavButtons) {
+            View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+                    mStartContextualContainer, mControllers.navButtonController, R.id.back);
+            imeDownButton.setRotation(Utilities.isRtl(resources) ? 90 : -90);
+            // Only show when IME is visible.
+            mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
+                    flags -> (flags & FLAG_IME_VISIBLE) != 0));
         }
+        mFloatingRotationButton = new FloatingRotationButton(
+                ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
+                R.string.accessibility_rotate_button,
+                R.layout.rotate_suggestion,
+                R.id.rotate_suggestion,
+                R.dimen.floating_rotation_button_min_margin,
+                R.dimen.rounded_corner_content_padding,
+                R.dimen.floating_rotation_button_taskbar_left_margin,
+                R.dimen.floating_rotation_button_taskbar_bottom_margin,
+                R.dimen.floating_rotation_button_diameter,
+                R.dimen.key_button_ripple_max_width,
+                R.bool.floating_rotation_button_position_left);
+        mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
+                mRotationButtonListener);
 
         applyState();
         mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
@@ -386,8 +376,15 @@
                             (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
                             (flags & FLAG_KEYGUARD_OCCLUDED) != 0;
                     return (flags & FLAG_DISABLE_BACK) == 0
+                            && (!mContext.isGestureNav() || !mContext.isUserSetupComplete())
                             && ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
                 }));
+        // Hide back button in SUW if keyboard is showing (IME draws its own back).
+        if (mIsImeRenderingNavButtons) {
+            mPropertyHolders.add(new StatePropertyHolder(
+                    mBackButtonAlpha.get(ALPHA_INDEX_SUW),
+                    flags -> (flags & FLAG_IME_VISIBLE) == 0));
+        }
         mPropertyHolders.add(new StatePropertyHolder(mBackButton,
                 flags -> (flags & FLAG_IME_VISIBLE) != 0,
                 ROTATION_DRAWABLE_PERCENT, 1f, 0f));
@@ -410,8 +407,8 @@
         mPropertyHolders.add(
                 new StatePropertyHolder(mHomeButtonAlpha.get(
                         ALPHA_INDEX_KEYGUARD_OR_DISABLE),
-                flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
-                        (flags & FLAG_DISABLE_HOME) == 0));
+                        flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
+                                && (flags & FLAG_DISABLE_HOME) == 0 && !mContext.isGestureNav()));
 
         // Recents button
         mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
@@ -429,7 +426,7 @@
         });
         mPropertyHolders.add(new StatePropertyHolder(mRecentsButton,
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
-                        && !mContext.isNavBarKidsModeActive()));
+                        && !mContext.isNavBarKidsModeActive() && !mContext.isGestureNav()));
 
         // A11y button
         mA11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
@@ -791,7 +788,6 @@
             NavButtonLayoutter navButtonLayoutter =
                     NavButtonLayoutFactory.Companion.getUiLayoutter(
                             dp, mNavButtonsView, mImeSwitcherButton,
-                            mControllers.rotationButtonController.getRotationButton(),
                             mA11yButton, mSpace, res, isInKidsMode, isInSetup, isThreeButtonNav,
                             mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
             navButtonLayoutter.layoutButtons(mContext, isA11yButtonPersistent());
@@ -802,13 +798,6 @@
 
         if (isInSetup) {
             handleSetupUi();
-
-            // Hide back button in SUW if keyboard is showing (IME draws its own back).
-            if (mIsImeRenderingNavButtons) {
-                mPropertyHolders.add(new StatePropertyHolder(
-                        mBackButtonAlpha.get(ALPHA_INDEX_SUW),
-                        flags -> (flags & FLAG_IME_VISIBLE) == 0));
-            }
         } else if (isInKidsMode) {
             int iconSize = res.getDimensionPixelSize(
                     R.dimen.taskbar_icon_size_kids);
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
index 83e4571..94e2244 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -15,9 +15,12 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Rect;
@@ -111,4 +114,17 @@
             setBackgroundColor(newColor);
         }
     }
+
+    /**
+     * Updates the handle scale.
+     *
+     * @param scale target scale to animate towards (starting from current scale)
+     * @param durationMs milliseconds for the animation to take
+     */
+    public void animateScale(float scale, long durationMs) {
+        ObjectAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+                PropertyValuesHolder.ofFloat(SCALE_PROPERTY, scale));
+        scaleAnim.setDuration(durationMs).setAutoCancel(true);
+        scaleAnim.start();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index f258b47..36e054a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -57,6 +57,10 @@
     public static final int ALPHA_INDEX_HIDDEN_WHILE_DREAMING = 3;
     private static final int NUM_ALPHA_CHANNELS = 4;
 
+    // Values for long press animations, picked to most closely match navbar spec.
+    private static final float SCALE_TOUCH_ANIMATION_SHRINK = 0.85f;
+    private static final float SCALE_TOUCH_ANIMATION_EXPAND = 1.18f;
+
     /**
      * The SharedPreferences key for whether the stashed handle region is dark.
      */
@@ -324,7 +328,13 @@
 
     @Override
     public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {
-        // TODO(b/308693847): Animate similarly to NavigationHandle.java (SysUI).
+        float targetScale;
+        if (isTouchDown) {
+            targetScale = shrink ? SCALE_TOUCH_ANIMATION_SHRINK : SCALE_TOUCH_ANIMATION_EXPAND;
+        } else {
+            targetScale = 1f;
+        }
+        mStashedHandleView.animateScale(targetScale, durationMs);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 49d4afe..af053e3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -41,6 +40,8 @@
 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
 
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
@@ -105,6 +106,7 @@
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 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.navbutton.NearestTouchFrame;
@@ -127,7 +129,9 @@
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.NavHandle;
+import com.android.quickstep.RecentsModel;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
@@ -244,8 +248,6 @@
 
         mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
 
-        final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
-
         // If Bubble bar is present, TaskbarControllers depends on it so build it first.
         Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
         BubbleBarController.onTaskbarRecreated();
@@ -258,7 +260,9 @@
                     new BubbleDragController(this),
                     new BubbleDismissController(this, mDragLayer),
                     new BubbleBarPinController(this, mDragLayer,
-                            () -> getDeviceProfile().getDisplayInfo().currentSize)
+                            () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
+                    new BubblePinController(this, mDragLayer,
+                            () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)
             ));
         }
 
@@ -271,16 +275,12 @@
                 R.drawable.ic_sysbar_rotate_button_cw_start_0,
                 R.drawable.ic_sysbar_rotate_button_cw_start_90,
                 () -> getDisplay().getRotation());
-        rotationButtonController.setBgExecutor(Executors.THREAD_POOL_EXECUTOR);
+        rotationButtonController.setBgExecutor(Executors.UI_HELPER_EXECUTOR);
 
         mControllers = new TaskbarControllers(this,
                 new TaskbarDragController(this),
                 buttonController,
-                isDesktopMode
-                        ? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
-                                navButtonsView)
-                        : new NavbarButtonsViewController(this, mNavigationBarPanelContext,
-                                navButtonsView),
+                new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView),
                 rotationButtonController,
                 new TaskbarDragLayerController(this, mDragLayer),
                 new TaskbarViewController(this, taskbarView),
@@ -301,17 +301,26 @@
                 new VoiceInteractionWindowController(this),
                 new TaskbarTranslationController(this),
                 new TaskbarSpringOnStashController(this),
-                isDesktopMode
-                        ? new DesktopTaskbarRecentAppsController(this)
-                        : TaskbarRecentAppsController.DEFAULT,
-                new TaskbarEduTooltipController(this),
+                createTaskbarRecentAppsController(),
+                TaskbarEduTooltipController.newInstance(this),
                 new KeyboardQuickSwitchController(),
-                new TaskbarPinningController(this),
+                new TaskbarPinningController(this, () ->
+                        DisplayController.INSTANCE.get(this).getInfo().isInDesktopMode()),
                 bubbleControllersOptional);
 
         mLauncherPrefs = LauncherPrefs.get(this);
     }
 
+    private TaskbarRecentAppsController createTaskbarRecentAppsController() {
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        if (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()) {
+            return new DesktopTaskbarRunningAppsController(
+                    RecentsModel.INSTANCE.get(this),
+                    LauncherActivityInterface.INSTANCE::getDesktopVisibilityController);
+        }
+        return TaskbarRecentAppsController.DEFAULT;
+    }
+
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
     public void updateDeviceProfile(DeviceProfile launcherDp) {
         applyDeviceProfile(launcherDp);
@@ -956,7 +965,9 @@
                 mWindowLayoutParams.paramsForRotation[rot].height = size;
             }
         }
-        mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
+        mControllers.runAfterInit(
+                mControllers.taskbarInsetsController
+                        ::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
         notifyUpdateLayoutParams();
     }
 
@@ -1442,7 +1453,7 @@
         });
     }
 
-    protected boolean isUserSetupComplete() {
+    public boolean isUserSetupComplete() {
         return mIsUserSetupComplete;
     }
 
@@ -1478,7 +1489,8 @@
             ((LauncherTaskbarUIController) uiController).addLauncherVisibilityChangedAnimation(
                     fullAnimation, duration);
         }
-        mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration);
+        mControllers.taskbarStashController.addUnstashToHotseatAnimationFromSuw(fullAnimation,
+                duration);
 
         View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
         if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 189b687..39f6fb2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -163,11 +163,6 @@
             return false;
         }
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick");
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.TWO_TASKBAR_LONG_CLICKS,
-                    "TaskbarDragController.startDragOnLongClick",
-                    new Throwable());
-        }
         BubbleTextView btv = (BubbleTextView) view;
         mActivity.onDragStart();
         btv.post(() -> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index e53f627..d43055d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar
 
+import android.content.Context
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
@@ -42,8 +43,10 @@
 import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
 import com.android.launcher3.util.DisplayController
-import com.android.launcher3.util.OnboardingPrefs.TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN
 import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.util.LottieAnimationColorUtils
 import java.io.PrintWriter
@@ -72,9 +75,11 @@
 annotation class TaskbarEduTooltipStep
 
 /** Controls stepping through the Taskbar tooltip EDU. */
-class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
-    LoggableTaskbarController {
+open class TaskbarEduTooltipController(context: Context) :
+    ResourceBasedOverride, LoggableTaskbarController {
 
+    protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+    open val shouldShowSearchEdu = false
     private val isTooltipEnabled: Boolean
         get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
     private val isOpen: Boolean
@@ -83,13 +88,13 @@
         get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
     private lateinit var controllers: TaskbarControllers
 
-    // Keep track of whether the user has seen the Circle to Search Edu
-    private var userHasSeenCircleToSearchEdu: Boolean
+    // Keep track of whether the user has seen the Search Edu
+    private var userHasSeenSearchEdu: Boolean
         get() {
-            return TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN.get(activityContext)
+            return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
         }
         private set(seen) {
-            LauncherPrefs.get(activityContext).put(TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN, seen)
+            LauncherPrefs.get(activityContext).put(TASKBAR_SEARCH_EDU_SEEN, seen)
         }
 
     @TaskbarEduTooltipStep
@@ -105,8 +110,8 @@
 
     fun init(controllers: TaskbarControllers) {
         this.controllers = controllers
-        // We want to show the Circle To Search Edu right after pinning, so we post it here
-        activityContext.dragLayer.post { maybeShowCircleToSearchEdu() }
+        // We want to show the Search Edu right after pinning the taskbar, so we post it here
+        activityContext.dragLayer.post { maybeShowSearchEdu() }
     }
 
     /** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
@@ -136,7 +141,7 @@
     fun maybeShowFeaturesEdu() {
         if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
             maybeShowPinningEdu()
-            maybeShowCircleToSearchEdu()
+            maybeShowSearchEdu()
             return
         }
 
@@ -233,26 +238,26 @@
     }
 
     /**
-     * Shows standalone Circle To Search EDU tooltip if this EDU has not been seen.
+     * Shows standalone Search EDU tooltip if this EDU has not been seen.
      *
-     * We show this standalone edu for users to learn to how to trigger Circle To Search from the
-     * pinned taskbar
+     * We show this standalone edu for users to learn to how to trigger Search from the pinned
+     * taskbar
      */
-    fun maybeShowCircleToSearchEdu() {
+    fun maybeShowSearchEdu() {
         if (
             !enableTaskbarPinning() ||
                 !DisplayController.isPinnedTaskbar(activityContext) ||
                 !isTooltipEnabled ||
-                userHasSeenCircleToSearchEdu
+                !shouldShowSearchEdu ||
+                userHasSeenSearchEdu
         ) {
             return
         }
-        userHasSeenCircleToSearchEdu = true
-        inflateTooltip(R.layout.taskbar_edu_circle_to_search)
+        userHasSeenSearchEdu = true
+        inflateTooltip(R.layout.taskbar_edu_search)
         tooltip?.run {
-            requireViewById<LottieAnimationView>(R.id.circle_to_search_animation)
-                .supportLightTheme()
-            val eduSubtitle: TextView = requireViewById(R.id.circle_to_search_text)
+            requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
+            val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
             showDisclosureText(eduSubtitle)
             updateLayoutParams<BaseDragLayer.LayoutParams> {
                 if (DisplayController.isTransientTaskbar(activityContext)) {
@@ -285,7 +290,7 @@
      */
     private fun TaskbarEduTooltip.showDisclosureText(
         textView: TextView,
-        stringId: Int = R.string.taskbar_edu_circle_to_search_disclosure,
+        stringId: Int = R.string.taskbar_edu_search_disclosure,
     ) {
         val locale = resources.configuration.locales[0]
         val text =
@@ -395,6 +400,17 @@
         pw?.println("$prefix\tisOpen=$isOpen")
         pw?.println("$prefix\ttooltipStep=$tooltipStep")
     }
+
+    companion object {
+        @JvmStatic
+        fun newInstance(context: Context): TaskbarEduTooltipController {
+            return ResourceBasedOverride.Overrides.getObject(
+                TaskbarEduTooltipController::class.java,
+                context,
+                R.string.taskbar_edu_tooltip_controller_class
+            )
+        }
+    }
 }
 
 /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 6163dad..4a8ed87 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -153,6 +153,19 @@
                 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)
+            }
         }
 
         // Pre-calculate insets for different providers across different rotations for this gravity
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 17dcace..6ea52cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -65,7 +65,7 @@
  */
 public class TaskbarLauncherStateController {
 
-    private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
+    private static final String TAG = "TaskbarLauncherStateController";
     private static final boolean DEBUG = false;
 
     /** Launcher activity is visible and focused. */
@@ -837,6 +837,7 @@
         appendFlag(result, flags, FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE,
                 "was_active_while_awake");
         appendFlag(result, flags, FLAG_DEVICE_LOCKED, "device_locked");
+        appendFlag(result, flags, FLAG_TASKBAR_HIDDEN, "taskbar_hidden");
         return result.toString();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index e47640b..42e6edb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar;
 
 import static android.content.Context.RECEIVER_NOT_EXPORTED;
-import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -26,6 +25,7 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
@@ -62,6 +62,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
 import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
@@ -70,7 +71,6 @@
 import com.android.quickstep.AllAppsActionManager;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.TouchInteractionService;
 import com.android.quickstep.util.AssistUtils;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
@@ -143,7 +143,7 @@
     private class RecreationListener implements DisplayController.DisplayInfoChangeListener {
         @Override
         public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
-            if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE
+            if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
                     | CHANGE_TASKBAR_PINNING)) != 0) {
                 recreateTaskbar();
             }
@@ -209,15 +209,18 @@
 
     @SuppressLint("WrongConstant")
     public TaskbarManager(
-            TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
+            Context context,
+            AllAppsActionManager allAppsActionManager,
+            TaskbarNavButtonCallbacks navCallbacks) {
+
         Display display =
-                service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
-        mContext = service.createWindowContext(display,
+                context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
+        mContext = context.createWindowContext(display,
                 ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
                 null);
         mAllAppsActionManager = allAppsActionManager;
         mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
-                ? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
+                ? context.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
                 : null;
         if (enableTaskbarNoRecreate()) {
             mWindowManager = mContext.getSystemService(WindowManager.class);
@@ -234,8 +237,11 @@
                 }
             };
         }
-        mNavButtonController = new TaskbarNavButtonController(service,
-                SystemUiProxy.INSTANCE.get(mContext), new Handler(),
+        mNavButtonController = new TaskbarNavButtonController(
+                context,
+                navCallbacks,
+                SystemUiProxy.INSTANCE.get(mContext),
+                new Handler(),
                 AssistUtils.newInstance(mContext));
         mComponentCallbacks = new ComponentCallbacks() {
             private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -420,9 +426,6 @@
      */
     private TaskbarUIController createTaskbarUIControllerForActivity(StatefulActivity activity) {
         if (activity instanceof QuickstepLauncher) {
-            if (mTaskbarActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
-                return new DesktopTaskbarUIController((QuickstepLauncher) activity);
-            }
             return new LauncherTaskbarUIController((QuickstepLauncher) activity);
         }
         if (activity instanceof RecentsActivity) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 14d46d1..9f24d38 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -15,6 +15,9 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+
 import android.util.SparseArray;
 import android.view.View;
 
@@ -26,6 +29,7 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -33,6 +37,7 @@
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.RecentsModel;
 
 import java.io.PrintWriter;
@@ -42,6 +47,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Predicate;
 
 /**
@@ -62,6 +68,8 @@
     // Used to defer any UI updates during the SUW unstash animation.
     private boolean mDeferUpdatesForSUW;
     private Runnable mDeferredUpdates;
+    private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+            visible -> updateRunningApps();
 
     public TaskbarModelCallbacks(
             TaskbarActivityContext context, TaskbarView container) {
@@ -73,6 +81,15 @@
         mControllers = controllers;
         if (mControllers.taskbarRecentAppsController.isEnabled()) {
             RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
+
+            if (shouldShowRunningAppsInDesktopMode()) {
+                DesktopVisibilityController desktopVisibilityController =
+                        LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+                if (desktopVisibilityController != null) {
+                    desktopVisibilityController.registerDesktopVisibilityListener(
+                            mDesktopVisibilityListener);
+                }
+            }
         }
     }
 
@@ -81,6 +98,20 @@
      */
     public void unregisterListeners() {
         RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
+
+        if (shouldShowRunningAppsInDesktopMode()) {
+            DesktopVisibilityController desktopVisibilityController =
+                    LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+            if (desktopVisibilityController != null) {
+                desktopVisibilityController.unregisterDesktopVisibilityListener(
+                        mDesktopVisibilityListener);
+            }
+        }
+    }
+
+    private boolean shouldShowRunningAppsInDesktopMode() {
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
     }
 
     @Override
@@ -203,15 +234,23 @@
         }
         hotseatItemInfos = mControllers.taskbarRecentAppsController
                 .updateHotseatItemInfos(hotseatItemInfos);
+        Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
 
         if (mDeferUpdatesForSUW) {
             ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
-            mDeferredUpdates = () -> mContainer.updateHotseatItems(finalHotseatItemInfos);
+            mDeferredUpdates = () ->
+                    commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages);
         } else {
-            mContainer.updateHotseatItems(hotseatItemInfos);
+            commitHotseatItemUpdates(hotseatItemInfos, runningPackages);
         }
     }
 
+    private void commitHotseatItemUpdates(
+            ItemInfo[] hotseatItemInfos, Set<String> runningPackages) {
+        mContainer.updateHotseatItems(hotseatItemInfos);
+        mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages);
+    }
+
     /**
      * This is used to defer UI updates after SUW builds the unstash animation.
      * @param defer if true, defers updates to the UI
@@ -240,7 +279,7 @@
 
     /** Call TaskbarRecentAppsController to update running apps with mHotseatItems. */
     public void updateRunningApps() {
-        mControllers.taskbarRecentAppsController.updateRunningApps(mHotseatItems);
+        mControllers.taskbarRecentAppsController.updateRunningApps();
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 03f55ca..13a68a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -31,6 +31,7 @@
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 
+import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
@@ -47,10 +48,8 @@
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.quickstep.LauncherActivityInterface;
-import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
-import com.android.quickstep.TouchInteractionService;
 import com.android.quickstep.util.AssistUtils;
 
 import java.io.PrintWriter;
@@ -67,7 +66,7 @@
     /** Allow some time in between the long press for back and recents. */
     static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
     static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
-    private static final String TAG = TaskbarNavButtonController.class.getSimpleName();
+    private static final String TAG = "TaskbarNavButtonController";
 
     private long mLastScreenPinLongPress;
     private boolean mScreenPinned;
@@ -106,7 +105,8 @@
     private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
     private int mLongPressedButtons = 0;
 
-    private final TouchInteractionService mService;
+    private final Context mContext;
+    private final TaskbarNavButtonCallbacks mCallbacks;
     private final SystemUiProxy mSystemUiProxy;
     private final Handler mHandler;
     private final AssistUtils mAssistUtils;
@@ -114,9 +114,14 @@
 
     private final Runnable mResetLongPress = this::resetScreenUnpin;
 
-    public TaskbarNavButtonController(TouchInteractionService service,
-            SystemUiProxy systemUiProxy, Handler handler, AssistUtils assistUtils) {
-        mService = service;
+    public TaskbarNavButtonController(
+            Context context,
+            TaskbarNavButtonCallbacks callbacks,
+            SystemUiProxy systemUiProxy,
+            Handler handler,
+            AssistUtils assistUtils) {
+        mContext = context;
+        mCallbacks = callbacks;
         mSystemUiProxy = systemUiProxy;
         mHandler = handler;
         mAssistUtils = assistUtils;
@@ -286,7 +291,7 @@
             desktopVisibilityController.onHomeActionTriggered();
         }
 
-        mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
+        mCallbacks.onNavigateHome();
     }
 
     private void navigateToOverview() {
@@ -295,7 +300,7 @@
         }
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-        mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+        mCallbacks.onToggleOverview();
     }
 
     private void executeBack() {
@@ -310,7 +315,7 @@
         if (longClick) {
             mSystemUiProxy.notifyAccessibilityButtonLongClicked();
         } else {
-            mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+            mSystemUiProxy.notifyAccessibilityButtonClicked(mContext.getDisplayId());
         }
     }
 
@@ -333,4 +338,13 @@
     private void showNotifications() {
         mSystemUiProxy.toggleNotificationPanel();
     }
+
+    /** Callbacks for navigation buttons on Taskbar. */
+    public interface TaskbarNavButtonCallbacks {
+        /** Callback invoked when the home button is pressed. */
+        default void onNavigateHome() {}
+
+        /** Callback invoked when the overview button is pressed. */
+        default void onToggleOverview() {}
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 2f2d636..6c9cc64 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -23,6 +23,7 @@
 import com.android.app.animation.Interpolators
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
@@ -31,8 +32,10 @@
 import java.io.PrintWriter
 
 /** Controls taskbar pinning through a popup view. */
-class TaskbarPinningController(private val context: TaskbarActivityContext) :
-    TaskbarControllers.LoggableTaskbarController {
+class TaskbarPinningController(
+    private val context: TaskbarActivityContext,
+    private val isInDesktopModeProvider: () -> Boolean,
+) : TaskbarControllers.LoggableTaskbarController {
 
     private lateinit var controllers: TaskbarControllers
     private lateinit var taskbarSharedState: TaskbarSharedState
@@ -54,14 +57,22 @@
                 if (!didPreferenceChange) {
                     return
                 }
+                val shouldPinTaskbar =
+                    if (isInDesktopModeProvider()) {
+                        !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+                    } else {
+                        !launcherPrefs.get(TASKBAR_PINNING)
+                    }
+
                 val animateToValue =
-                    if (!launcherPrefs.get(TASKBAR_PINNING)) {
+                    if (shouldPinTaskbar) {
                         statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
                         PINNING_PERSISTENT
                     } else {
                         statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
                         PINNING_TRANSIENT
                     }
+
                 taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
                 animateTaskbarPinning(animateToValue)
             }
@@ -123,13 +134,24 @@
     @VisibleForTesting
     fun recreateTaskbarAndUpdatePinningValue() {
         updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
-        launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
+        if (isInDesktopModeProvider()) {
+            launcherPrefs.put(
+                TASKBAR_PINNING_IN_DESKTOP_MODE,
+                !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+            )
+        } else {
+            launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
+        }
     }
 
     override fun dumpLogs(prefix: String, pw: PrintWriter) {
         pw.println(prefix + "TaskbarPinningController:")
         pw.println("$prefix\tisAnimatingTaskbarPinning=$isAnimatingTaskbarPinning")
         pw.println("$prefix\tTASKBAR_PINNING shared pref =" + launcherPrefs.get(TASKBAR_PINNING))
+        pw.println(
+            "$prefix\tTASKBAR_PINNING_IN_DESKTOP_MODE shared pref in desktop mode =" +
+                launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+        )
     }
 
     companion object {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
index 8445cff..a29c74b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
@@ -15,13 +15,16 @@
  */
 package com.android.launcher3.taskbar;
 
-import android.util.SparseArray;
+import static java.util.Collections.emptySet;
 
 import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
 
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 
+import java.util.Set;
+
 /**
  * Base class for providing recent apps functionality
  */
@@ -43,7 +46,8 @@
     }
 
     /** Stores the current {@link AppInfo} instances, no-op except in desktop environment. */
-    protected void setApps(AppInfo[] apps) { }
+    protected void setApps(AppInfo[] apps) {
+    }
 
     /**
      * Indicates whether recent apps functionality is enabled, should return false except in
@@ -54,10 +58,15 @@
     }
 
     /** Called to update hotseatItems, no-op except in desktop environment. */
-    protected ItemInfo[] updateHotseatItemInfos(ItemInfo[] hotseatItems) {
+    protected ItemInfo[] updateHotseatItemInfos(@NonNull ItemInfo[] hotseatItems) {
         return hotseatItems;
     }
 
     /** Called to update the list of currently running apps, no-op except in desktop environment. */
-    protected void updateRunningApps(SparseArray<ItemInfo> hotseatItems) { }
+    protected void updateRunningApps() {}
+
+    /** Returns the currently running apps, or an empty Set if outside of Desktop environment. */
+    public Set<String> getRunningApps() {
+        return emptySet();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 15be8e7..f764a83 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -78,13 +78,13 @@
  * create a cohesive animation between stashed/unstashed states.
  */
 public class TaskbarStashController implements TaskbarControllers.LoggableTaskbarController {
-    private static final String TAG = TaskbarStashController.class.getSimpleName();
+    private static final String TAG = "TaskbarStashController";
     private static final boolean DEBUG = false;
 
     public static final int FLAG_IN_APP = 1 << 0;
     public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 1; // shade open, ...
     public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 2; // setup wizard and AllSetActivity
-    public static final int FLAG_STASHED_IN_APP_IME = 1 << 3; // IME is visible
+    public static final int FLAG_STASHED_IME = 1 << 3; // IME is visible
     public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 4;
     public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 5; // All apps is visible.
     public static final int FLAG_IN_SETUP = 1 << 6; // In the Setup Wizard
@@ -99,21 +99,19 @@
 
     // If we're in an app and any of these flags are enabled, taskbar should be stashed.
     private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_SYSUI
-            | FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_APP_IME
-            | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN
-            | FLAG_STASHED_IN_APP_AUTO;
+            | FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_TASKBAR_ALL_APPS
+            | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
 
     // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
     // height. This way the reported insets are consistent even during transitions out of the app.
     // Currently any flag that causes us to stash in an app is included, except for IME or All Apps
     // since those cover the underlying app anyway and thus the app shouldn't change insets.
     private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
-            & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS
-            & ~FLAG_STASHED_IN_APP_SYSUI;
+            & ~FLAG_STASHED_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS & ~FLAG_STASHED_IN_APP_SYSUI;
 
     // If any of these flags are enabled, the taskbar must be stashed.
     private static final int FLAGS_FORCE_STASHED = FLAG_STASHED_SYSUI | FLAG_STASHED_DEVICE_LOCKED
-            | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN;
+            | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IME;
 
     /**
      * How long to stash/unstash when manually invoked via long press.
@@ -321,8 +319,7 @@
         updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isStashedInAppAuto);
         updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
         updateStateForFlag(FLAG_IN_SETUP, isInSetup);
-        updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, mActivity.isPhoneMode()
-                && !mActivity.isThreeButtonNav());
+        updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, mActivity.isPhoneGestureNavMode());
         // For now, assume we're in an app, since LauncherTaskbarUIController won't be able to tell
         // us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
         updateStateForFlag(FLAG_IN_APP, true);
@@ -549,11 +546,12 @@
      *                            sub-animations are properly coordinated. This duration should not
      *                            actually be used since this animation tracks a swipe progress.
      */
-    protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
+    protected void addUnstashToHotseatAnimationFromSuw(AnimatorSet animation,
+            int placeholderDuration) {
         // Defer any UI updates now to avoid the UI becoming stale when the animation plays.
         mControllers.taskbarViewController.setDeferUpdatesForSUW(true);
         createAnimToIsStashed(
-                /* isStashed= */ false,
+                /* isStashed= */ mActivity.isPhoneMode(),
                 placeholderDuration,
                 TRANSITION_UNSTASH_SUW_MANUAL,
                 /* jankTag= */ "SUW_MANUAL");
@@ -598,7 +596,7 @@
                             ? stashTranslation : 0)
                     .setDuration(duration));
             mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
-                    (hasAnyFlag(FLAG_STASHED_IN_APP_IME) && isStashed) ? 0 : 1).setDuration(
+                    (hasAnyFlag(FLAG_STASHED_IME) && isStashed) ? 0 : 1).setDuration(
                     duration));
             mAnimator.addListener(AnimatorListeners.forEndCallback(() -> {
                 mAnimator = null;
@@ -901,8 +899,8 @@
 
     private void setStashedImeState() {
         boolean shouldStashForIme = shouldStashForIme();
-        if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
-            updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme);
+        if (hasAnyFlag(FLAG_STASHED_IME) != shouldStashForIme) {
+            updateStateForFlag(FLAG_STASHED_IME, shouldStashForIme);
             applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
         } else {
             applyState(mControllers.taskbarOverlayController.getCloseDuration());
@@ -949,7 +947,7 @@
 
         mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
         mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
-        if (updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme())) {
+        if (updateStateForFlag(FLAG_STASHED_IME, shouldStashForIme())) {
             animDuration = TASKBAR_STASH_DURATION_FOR_IME;
             startDelay = getTaskbarStashStartDelayForIme();
         }
@@ -1158,13 +1156,14 @@
         appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_SYSUI, "FLAG_STASHED_IN_APP_SYSUI");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
-        appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
+        appendFlag(sj, flags, FLAG_STASHED_IME, "FLAG_STASHED_IN_APP_IME");
         appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
         appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS");
         appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO");
         appendFlag(sj, flags, FLAG_STASHED_SYSUI, "FLAG_STASHED_SYSUI");
         appendFlag(sj, flags, FLAG_STASHED_DEVICE_LOCKED, "FLAG_STASHED_DEVICE_LOCKED");
+        appendFlag(sj, flags, FLAG_IN_OVERVIEW, "FLAG_IN_OVERVIEW");
         return sj.toString();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2e78489..6abd5a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -44,7 +44,7 @@
 import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.io.PrintWriter;
@@ -55,7 +55,6 @@
  * Base class for providing different taskbar UI
  */
 public class TaskbarUIController {
-
     public static final TaskbarUIController DEFAULT = new TaskbarUIController();
 
     // Initialized in init.
@@ -91,6 +90,10 @@
      */
     protected void onIconLayoutBoundsChanged() { }
 
+    protected String getTaskbarUIControllerName() {
+        return "TaskbarUIController";
+    }
+
     /** Called when an icon is launched. */
     @CallSuper
     public void onTaskbarIconLaunched(ItemInfo item) {
@@ -207,7 +210,7 @@
         pw.println(String.format(
                 "%sTaskbarUIController: using an instance of %s",
                 prefix,
-                getClass().getSimpleName()));
+                getTaskbarUIControllerName()));
     }
 
     /**
@@ -259,14 +262,14 @@
                         if (foundTaskView != null) {
                             // There is already a running app of this type, use that as second app.
                             // Get index of task (0 or 1), in case it's a GroupedTaskView
-                            TaskIdAttributeContainer taskAttributes =
-                                    foundTaskView.getTaskAttributesById(foundTask.key.id);
+                            TaskContainer taskContainer =
+                                    foundTaskView.getTaskContainerById(foundTask.key.id);
                             recents.confirmSplitSelect(
                                     foundTaskView,
                                     foundTask,
-                                    taskAttributes.getIconView().getDrawable(),
-                                    taskAttributes.getThumbnailView(),
-                                    taskAttributes.getThumbnailView().getThumbnail(),
+                                    taskContainer.getIconView().getDrawable(),
+                                    taskContainer.getThumbnailView(),
+                                    taskContainer.getThumbnailView().getThumbnail(),
                                     null /* intent */,
                                     null /* user */,
                                     info);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index effef3c..df7a7ba 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
 import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
@@ -72,7 +71,7 @@
  */
 public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
         DeviceProfile.OnDeviceProfileChangeListener {
-    private static final String TAG = TaskbarView.class.getSimpleName();
+    private static final String TAG = "TaskbarView";
 
     private static final Rect sTmpRect = new Rect();
 
@@ -157,23 +156,21 @@
         // Needed to draw folder leave-behind when opening one.
         setWillNotDraw(false);
 
-        if (!mActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
-            mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
-                    .inflate(R.layout.taskbar_all_apps_button, this, false);
-            mAllAppsButton.setIconDrawable(resources.getDrawable(
-                    getAllAppsButton(isTransientTaskbar)));
-            mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
-            mAllAppsButton.setForegroundTint(
-                    mActivityContext.getColor(R.color.all_apps_button_color));
+        mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
+                .inflate(R.layout.taskbar_all_apps_button, this, false);
+        mAllAppsButton.setIconDrawable(resources.getDrawable(
+                getAllAppsButton(isTransientTaskbar)));
+        mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+        mAllAppsButton.setForegroundTint(
+                mActivityContext.getColor(R.color.all_apps_button_color));
 
-            if (enableTaskbarPinning()) {
-                mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
-                        R.layout.taskbar_divider,
-                        this, false);
-                mTaskbarDivider.setIconDrawable(
-                        resources.getDrawable(R.drawable.taskbar_divider_button));
-                mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
-            }
+        if (enableTaskbarPinning()) {
+            mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
+                    R.layout.taskbar_divider,
+                    this, false);
+            mTaskbarDivider.setIconDrawable(
+                    resources.getDrawable(R.drawable.taskbar_divider_button));
+            mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
         }
 
         // TODO: Disable touch events on QSB otherwise it can crash.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index ecd20d4..93814b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -72,6 +72,7 @@
 import com.android.launcher3.views.IconButtonView;
 
 import java.io.PrintWriter;
+import java.util.Set;
 import java.util.function.Predicate;
 
 /**
@@ -79,7 +80,7 @@
  */
 public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController {
 
-    private static final String TAG = TaskbarViewController.class.getSimpleName();
+    private static final String TAG = "TaskbarViewController";
 
     private static final Runnable NO_OP = () -> { };
 
@@ -508,6 +509,15 @@
         return mTaskbarView.getTaskbarDividerView();
     }
 
+    /** Updates which icons are marked as running given the Set of currently running packages. */
+    public void updateIconViewsRunningStates(Set<String> runningPackages) {
+        for (View iconView : getIconViews()) {
+            if (iconView instanceof BubbleTextView btv) {
+                btv.updateRunningState(runningPackages.contains(btv.getTargetPackageName()));
+            }
+        }
+    }
+
     /**
      * Defers any updates to the UI for the setup wizard animation.
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 6ceec3e..8e05686 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -207,13 +207,6 @@
     }
 
     @Override
-    protected void onUserSwipeToDismissProgressChanged() {
-        super.onUserSwipeToDismissProgressChanged();
-        mAppsView.setClipChildren(!mIsDismissInProgress);
-        mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
-    }
-
-    @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         setTranslationShift(mTranslationShift);
@@ -259,12 +252,28 @@
         return getPopupContainer().isEventOverView(mAppsView.getVisibleContainerView(), ev);
     }
 
+    /**
+     * In taskbar all apps search mode, we should scale down content inside all apps, rather
+     * than the whole all apps bottom sheet, to indicate we will navigate back within the all apps.
+     */
+    @Override
+    public boolean shouldAnimateContentViewInBackSwipe() {
+        return mAllAppsCallbacks.canHandleSearchBackInvoked();
+    }
+
+    @Override
+    protected void onUserSwipeToDismissProgressChanged() {
+        super.onUserSwipeToDismissProgressChanged();
+        mAppsView.setClipChildren(!mIsDismissInProgress);
+        mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
+    }
+
     @Override
     public void onBackInvoked() {
         if (mAllAppsCallbacks.handleSearchBackInvoked()) {
             // We need to scale back taskbar all apps if we navigate back within search inside all
             // apps
-            animateSwipeToDismissProgressToStart();
+            post(this::animateSwipeToDismissProgressToStart);
         } else {
             super.onBackInvoked();
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index ba4fa45..52f7176 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -143,6 +143,11 @@
             }
         }
 
+        /** Check if search session can handle back. This check doesn't perform any action. */
+        boolean canHandleSearchBackInvoked() {
+            return mSearchSessionController.canHandleBackInvoked();
+        }
+
         /** Invoked on back press, returning {@code true} if the search session handled it. */
         boolean handleSearchBackInvoked() {
             return mSearchSessionController.handleBackInvoked();
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 3d15fbd..4d0b376 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -49,6 +49,8 @@
     /** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */
     open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null
 
+    open fun canHandleBackInvoked(): Boolean = false
+
     open fun handleBackInvoked(): Boolean = false
 
     open fun onAllAppsAnimationPending(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 8eeb055..a59e81b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -22,22 +22,24 @@
 import android.graphics.Paint
 import android.graphics.PixelFormat
 import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
 import com.android.app.animation.Interpolators
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.mapToRange
 import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.wm.shell.common.TriangleShape
+import com.android.launcher3.popup.RoundedArrowDrawable
 
 /** Drawable for the background of the bubble bar. */
-class BubbleBarBackground(context: Context, private val backgroundHeight: Float) : Drawable() {
+class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
 
     private val DARK_THEME_SHADOW_ALPHA = 51f
     private val LIGHT_THEME_SHADOW_ALPHA = 25f
 
     private val paint: Paint = Paint()
-    private val pointerSize: Float
+    private val pointerWidth: Float
+    private val pointerHeight: Float
+    private val pointerTipRadius: Float
+    private val pointerVisibleHeight: Float
 
     private val shadowAlpha: Float
     private var shadowBlur = 0f
@@ -47,7 +49,7 @@
         private set
 
     private var showingArrow: Boolean = false
-    private var arrowDrawable: ShapeDrawable
+    private var arrowDrawable: RoundedArrowDrawable
 
     var width: Float = 0f
 
@@ -75,7 +77,10 @@
         val res = context.resources
         shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
         keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
-        pointerSize = res.getDimension(R.dimen.bubblebar_pointer_size)
+        pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+        pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+        pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+        pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
 
         shadowAlpha =
             if (Utilities.isDarkTheme(context)) {
@@ -85,11 +90,14 @@
             }
 
         arrowDrawable =
-            ShapeDrawable(TriangleShape.create(pointerSize, pointerSize, /* pointUp= */ true))
-        arrowDrawable.setBounds(0, 0, pointerSize.toInt(), pointerSize.toInt())
-        arrowDrawable.paint.flags = Paint.ANTI_ALIAS_FLAG
-        arrowDrawable.paint.style = Paint.Style.FILL
-        arrowDrawable.paint.color = context.getColor(R.color.taskbar_background)
+            RoundedArrowDrawable.createVerticalRoundedArrow(
+                pointerWidth,
+                pointerHeight,
+                pointerTipRadius,
+                /* isPointingUp= */ true,
+                context.getColor(R.color.taskbar_background)
+            )
+        arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
     }
 
     fun showArrow(show: Boolean) {
@@ -114,7 +122,7 @@
             keyShadowDistance,
             setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
         )
-        arrowDrawable.paint.setShadowLayer(
+        arrowDrawable.setShadowLayer(
             shadowBlur,
             0f,
             keyShadowDistance,
@@ -123,24 +131,16 @@
 
         // Draw background.
         val radius = backgroundHeight / 2f
-        val left = if (anchorLeft) 0f else bounds.width().toFloat() - width
-        val right = if (anchorLeft) width else bounds.width().toFloat()
-        canvas.drawRoundRect(
-            left,
-            pointerSize,
-            right,
-            bounds.height().toFloat(),
-            radius,
-            radius,
-            paint
-        )
+        val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
+        val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
+        val top = bounds.top + pointerVisibleHeight
+        val bottom = bounds.top + bounds.height().toFloat()
+        canvas.drawRoundRect(left, top, right, bottom, radius, radius, paint)
 
         if (showingArrow) {
             // Draw arrow.
-            val transX = arrowPositionX - pointerSize / 2f
-            // Shift arrow down by 1 pixel. Rounded rect has a 1 pixel border which will show up
-            // between background and arrow otherwise.
-            canvas.translate(transX, 1f)
+            val transX = bounds.left + arrowPositionX - pointerWidth / 2f
+            canvas.translate(transX, 0f)
             arrowDrawable.draw(canvas)
         }
 
@@ -157,7 +157,8 @@
 
     override fun setAlpha(alpha: Int) {
         paint.alpha = alpha
-        arrowDrawable.paint.alpha = alpha
+        arrowDrawable.alpha = alpha
+        invalidateSelf()
     }
 
     override fun getAlpha(): Int {
@@ -169,6 +170,10 @@
     }
 
     fun setArrowAlpha(alpha: Int) {
-        arrowDrawable.paint.alpha = alpha
+        arrowDrawable.alpha = alpha
+    }
+
+    fun setHeight(newHeight: Float) {
+        backgroundHeight = newHeight
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a2c1b07..5789f0c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -94,7 +94,7 @@
  */
 public class BubbleBarController extends IBubblesListener.Stub {
 
-    private static final String TAG = BubbleBarController.class.getSimpleName();
+    private static final String TAG = "BubbleBarController";
     private static final boolean DEBUG = false;
 
     /**
@@ -150,6 +150,7 @@
     private BubbleBarViewController mBubbleBarViewController;
     private BubbleStashController mBubbleStashController;
     private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
+    private BubblePinController mBubblePinController;
 
     // Keep track of bubble bar bounds sent to shell to avoid sending duplicate updates
     private final Rect mLastSentBubbleBarBounds = new Rect();
@@ -169,6 +170,7 @@
         BubbleBarLocation bubbleBarLocation;
         List<RemovedBubble> removedBubbles;
         List<String> bubbleKeysInOrder;
+        Point expandedViewDropTargetSize;
 
         // These need to be loaded in the background
         BubbleBarBubble addedBubble;
@@ -186,6 +188,7 @@
             bubbleBarLocation = update.bubbleBarLocation;
             removedBubbles = update.removedBubbles;
             bubbleKeysInOrder = update.bubbleKeysInOrder;
+            expandedViewDropTargetSize = update.expandedViewDropTargetSize;
         }
     }
 
@@ -216,6 +219,7 @@
         mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
         mBubbleStashController = bubbleControllers.bubbleStashController;
         mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
+        mBubblePinController = bubbleControllers.bubblePinController;
 
         bubbleControllers.runAfterInit(() -> {
             mBubbleBarViewController.setHiddenForBubbles(
@@ -313,8 +317,11 @@
                 || (!update.expandedChanged && !mBubbleBarViewController.isExpanded());
         final boolean isExpanding = update.expandedChanged && update.expanded;
         // don't animate bubbles if this is the initial state because we may be unfolding or
-        // enabling gesture nav
-        final boolean suppressAnimation = update.initialState;
+        // enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g.
+        // the shade is open, or we're locked.
+        final boolean suppressAnimation =
+                update.initialState || mBubbleBarViewController.isHiddenForSysui();
+
         BubbleBarItem previouslySelectedBubble = mSelectedBubble;
         BubbleBarBubble bubbleToSelect = null;
         if (!update.removedBubbles.isEmpty()) {
@@ -400,9 +407,6 @@
         }
         if (bubbleToSelect != null) {
             setSelectedBubbleInternal(bubbleToSelect);
-            if (previouslySelectedBubble == null) {
-                mBubbleStashController.animateToInitialState(update.expanded);
-            }
         }
         if (update.shouldShowEducation) {
             mBubbleBarViewController.prepareToShowEducation();
@@ -416,11 +420,12 @@
         }
         if (update.bubbleBarLocation != null) {
             if (update.bubbleBarLocation != mBubbleBarViewController.getBubbleBarLocation()) {
-                // Animate when receiving updates. Skip it if we received the initial state.
-                boolean animate = !update.initialState;
-                updateBubbleBarLocationInternal(update.bubbleBarLocation, animate);
+                updateBubbleBarLocationInternal(update.bubbleBarLocation);
             }
         }
+        if (update.expandedViewDropTargetSize != null) {
+            mBubblePinController.setDropTargetSize(update.expandedViewDropTargetSize);
+        }
     }
 
     /** Tells WMShell to show the currently selected bubble. */
@@ -480,15 +485,21 @@
      * Updates the value locally in Launcher and in WMShell.
      */
     public void updateBubbleBarLocation(BubbleBarLocation location) {
-        updateBubbleBarLocationInternal(location, false /* animate */);
+        updateBubbleBarLocationInternal(location);
         mSystemUiProxy.setBubbleBarLocation(location);
     }
 
-    private void updateBubbleBarLocationInternal(BubbleBarLocation location, boolean animate) {
-        mBubbleBarViewController.setBubbleBarLocation(location, animate);
+    private void updateBubbleBarLocationInternal(BubbleBarLocation location) {
+        mBubbleBarViewController.setBubbleBarLocation(location);
         mBubbleStashController.setBubbleBarLocation(location);
     }
 
+    @Override
+    public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        mMainExecutor.execute(
+                () -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
+    }
+
     //
     // Loading data for the bubbles
     //
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index 8ed9949..9e5ffc9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -19,7 +19,6 @@
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Point
-import android.graphics.RectF
 import android.view.Gravity.BOTTOM
 import android.view.Gravity.LEFT
 import android.view.Gravity.RIGHT
@@ -37,44 +36,29 @@
 class BubbleBarPinController(
     private val context: Context,
     private val container: FrameLayout,
-    private val screenSizeProvider: () -> Point
-) : BaseBubblePinController() {
+    screenSizeProvider: () -> Point
+) : BaseBubblePinController(screenSizeProvider) {
 
     private lateinit var bubbleBarViewController: BubbleBarViewController
     private lateinit var bubbleStashController: BubbleStashController
+    private var exclRectWidth: Float = 0f
+    private var exclRectHeight: Float = 0f
+
     private var dropTargetView: View? = null
 
     fun init(bubbleControllers: BubbleControllers) {
         bubbleBarViewController = bubbleControllers.bubbleBarViewController
         bubbleStashController = bubbleControllers.bubbleStashController
+        exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width)
+        exclRectHeight = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
     }
 
-    override fun getScreenCenterX(): Int {
-        return screenSizeProvider.invoke().x / 2
+    override fun getExclusionRectWidth(): Float {
+        return exclRectWidth
     }
 
-    override fun getExclusionRect(): RectF {
-        val rect =
-            RectF(
-                0f,
-                0f,
-                context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width),
-                context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
-            )
-        val screenSize = screenSizeProvider.invoke()
-        val middleX = screenSize.x / 2
-        // Center it around the bottom center of the screen
-        rect.offsetTo(middleX - rect.width() / 2, screenSize.y - rect.height())
-        return rect
-    }
-
-    override fun createDropTargetView(): View {
-        return LayoutInflater.from(context)
-            .inflate(R.layout.bubble_bar_drop_target, container, false)
-            .also { view ->
-                dropTargetView = view
-                container.addView(view)
-            }
+    override fun getExclusionRectHeight(): Float {
+        return exclRectHeight
     }
 
     override fun getDropTargetView(): View? {
@@ -86,6 +70,15 @@
         dropTargetView = null
     }
 
+    override fun createDropTargetView(): View {
+        return LayoutInflater.from(context)
+            .inflate(R.layout.bubble_bar_drop_target, container, false)
+            .also { view ->
+                dropTargetView = view
+                container.addView(view)
+            }
+    }
+
     @SuppressLint("RtlHardcoded")
     override fun updateLocation(location: BubbleBarLocation) {
         val onLeft = location.isOnLeft(container.isLayoutRtl)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 711ba62..d08015e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar.bubbles;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
 
 import android.animation.Animator;
@@ -29,6 +30,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.LayoutDirection;
 import android.util.Log;
 import android.view.Gravity;
@@ -74,11 +76,12 @@
  */
 public class BubbleBarView extends FrameLayout {
 
-    private static final String TAG = BubbleBarView.class.getSimpleName();
+    private static final String TAG = "BubbleBarView";
 
     // TODO: (b/273594744) calculate the amount of space we have and base the max on that
     //  if it's smaller than 5.
     private static final int MAX_BUBBLES = 5;
+    private static final int MAX_VISIBLE_BUBBLES_COLLAPSED = 2;
     private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
     private static final int WIDTH_ANIMATION_DURATION_MS = 200;
 
@@ -94,6 +97,23 @@
     // During fade in animation we shift the bubble bar 1/60th of the screen width
     private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
 
+    /**
+     * Custom property to set alpha value for the bar view while a bubble is being dragged.
+     * Skips applying alpha to the dragged bubble.
+     */
+    private static final FloatProperty<BubbleBarView> BUBBLE_DRAG_ALPHA =
+            new FloatProperty<>("bubbleDragAlpha") {
+                @Override
+                public void setValue(BubbleBarView bubbleBarView, float alpha) {
+                    bubbleBarView.setAlphaDuringBubbleDrag(alpha);
+                }
+
+                @Override
+                public Float get(BubbleBarView bubbleBarView) {
+                    return bubbleBarView.mAlphaDuringDrag;
+                }
+            };
+
     private final BubbleBarBackground mBubbleBarBackground;
 
     private boolean mIsAnimatingNewBubble = false;
@@ -106,18 +126,23 @@
     private final Rect mBubbleBarBounds = new Rect();
     // The amount the bubbles overlap when they are stacked in the bubble bar
     private final float mIconOverlapAmount;
-    // The spacing between the bubbles when they are expanded in the bubble bar
-    private final float mIconSpacing;
+    // The spacing between the bubbles when bubble bar is expanded
+    private final float mExpandedBarIconsSpacing;
+    // The spacing between the bubbles and the borders of the bubble bar
+    private float mBubbleBarPadding;
     // The size of a bubble in the bar
-    private final float mIconSize;
+    private float mIconSize;
     // The elevation of the bubbles within the bar
     private final float mBubbleElevation;
     private final float mDragElevation;
     private final int mPointerSize;
 
+    private final Rect mTempBackgroundBounds = new Rect();
+
     // Whether the bar is expanded (i.e. the bubble activity is being displayed).
     private boolean mIsBarExpanded = false;
     // The currently selected bubble view.
+    @Nullable
     private BubbleView mSelectedBubbleView;
     private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
     // The click listener when the bubble bar is collapsed.
@@ -147,11 +172,10 @@
 
     @Nullable
     private BubbleView mDraggedBubbleView;
+    private float mAlphaDuringDrag = 1f;
 
     private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
 
-    private boolean mLocationChangePending;
-
     public BubbleBarView(Context context) {
         this(context, null);
     }
@@ -169,21 +193,23 @@
         setAlpha(0);
         setVisibility(INVISIBLE);
         mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
-        mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+        mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
         mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+        mExpandedBarIconsSpacing = getResources().getDimensionPixelSize(
+                R.dimen.bubblebar_expanded_icon_spacing);
         mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
         mDragElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
-        mPointerSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_pointer_size);
+        mPointerSize = getResources()
+                .getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size);
 
         setClipToPadding(false);
 
-        mBubbleBarBackground = new BubbleBarBackground(context,
-                getResources().getDimensionPixelSize(R.dimen.bubblebar_size));
+        mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarExpandedHeight());
         setBackgroundDrawable(mBubbleBarBackground);
 
         mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
         mWidthAnimator.addUpdateListener(animation -> {
-            updateChildrenRenderNodeProperties();
+            updateChildrenRenderNodeProperties(mBubbleBarLocation);
             invalidate();
         });
         mWidthAnimator.addListener(new Animator.AnimatorListener() {
@@ -201,6 +227,7 @@
                 // If the bar was just collapsed and the overflow was the last bubble that was
                 // selected, set the first bubble as selected.
                 if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
+                        && mSelectedBubbleView != null
                         && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
                     BubbleView firstBubble = (BubbleView) getChildAt(0);
                     mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
@@ -220,6 +247,40 @@
     }
 
     @Override
+    public void setTranslationX(float translationX) {
+        super.setTranslationX(translationX);
+        if (mDraggedBubbleView != null) {
+            // Apply reverse of the translation as an offset to the dragged view. This ensures
+            // that the dragged bubble stays at the current location on the screen and its
+            // position is not affected by the parent translation.
+            mDraggedBubbleView.setOffsetX(-translationX);
+        }
+    }
+
+    /**
+     * Sets new icon size and spacing between icons and bubble bar borders.
+     *
+     * @param newIconSize new icon size
+     * @param spacing     spacing between icons and bubble bar borders.
+     */
+    // TODO(b/335575529): animate bubble bar icons size change
+    public void setIconSizeAndPadding(float newIconSize, float spacing) {
+        // TODO(b/335457839): handle new bubble animation during the size change
+        mBubbleBarPadding = spacing;
+        mIconSize = newIconSize;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View childView = getChildAt(i);
+            FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
+            params.height = (int) mIconSize;
+            params.width = (int) mIconSize;
+            childView.setLayoutParams(params);
+        }
+        mBubbleBarBackground.setHeight(getBubbleBarExpandedHeight());
+        updateLayoutParams();
+    }
+
+    @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         mBubbleBarBounds.left = left;
@@ -232,8 +293,10 @@
         setPivotX(mRelativePivotX * getWidth());
         setPivotY(mRelativePivotY * getHeight());
 
-        // Position the views
-        updateChildrenRenderNodeProperties();
+        if (!mDragging) {
+            // Position the views when not dragging
+            updateChildrenRenderNodeProperties(mBubbleBarLocation);
+        }
     }
 
     @Override
@@ -249,15 +312,12 @@
 
     @SuppressLint("RtlHardcoded")
     private void onBubbleBarLocationChanged() {
-        mLocationChangePending = false;
         final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
         mBubbleBarBackground.setAnchorLeft(onLeft);
         mRelativePivotX = onLeft ? 0f : 1f;
-        if (getLayoutParams() instanceof LayoutParams lp) {
-            lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
-            setLayoutParams(lp);
-        }
-        invalidate();
+        LayoutParams lp = (LayoutParams) getLayoutParams();
+        lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
+        setLayoutParams(lp); // triggers a relayout
     }
 
     /**
@@ -270,16 +330,16 @@
     /**
      * Update {@link BubbleBarLocation}
      */
-    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
-        if (animate) {
-            animateToBubbleBarLocation(bubbleBarLocation);
-        } else {
-            setBubbleBarLocationInternal(bubbleBarLocation);
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        resetDragAnimation();
+        if (bubbleBarLocation != mBubbleBarLocation) {
+            mBubbleBarLocation = bubbleBarLocation;
+            onBubbleBarLocationChanged();
         }
     }
 
     /**
-     * Set whether this view is being currently being dragged
+     * Set whether this view is currently being dragged
      */
     public void setIsDragging(boolean dragging) {
         if (mDragging == dragging) {
@@ -287,51 +347,65 @@
         }
         mDragging = dragging;
         setElevation(dragging ? mDragElevation : mBubbleElevation);
-        if (!dragging && mLocationChangePending) {
-            // During drag finish animation we may update the translation x value to shift the
-            // bubble to the new drop target. Clear the translation here.
-            setTranslationX(0f);
-            onBubbleBarLocationChanged();
+        if (!mDragging) {
+            // Relayout after dragging to ensure that the dragged bubble is positioned correctly
+            requestLayout();
         }
     }
 
     /**
-     * Adjust resting position for the bubble bar while it is being dragged.
-     * <p>
-     * Bubble bar is laid out on left or right side of the screen. When it is being dragged to
-     * the opposite side, the resting position should be on that side. Calculate any additional
-     * translation that may be required to move the bubble bar to the new side.
+     * Get translation for bubble bar when drag is released and it needs to animate back to the
+     * resting position.
+     * Resting position is based on the supplied location. If the supplied location is different
+     * from the internal location that was used during bubble bar layout, translation values are
+     * calculated to position the bar at the desired location.
      *
-     * @param restingPosition relative resting position of the bubble bar from the laid out position
+     * @param initialTranslation initial bubble bar translation at the start of drag
+     * @param location           desired location of the bubble bar when drag is released
+     * @return point with x and y values representing translation on x and y-axis
      */
-    @SuppressLint("RtlHardcoded")
-    void adjustRelativeRestingPosition(PointF restingPosition) {
-        final boolean locationOnLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
-        // Bubble bar is placed left or right with gravity. Check where it is currently.
-        final int absoluteGravity = Gravity.getAbsoluteGravity(
-                ((LayoutParams) getLayoutParams()).gravity, getLayoutDirection());
-        final boolean gravityOnLeft =
-                (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT;
-
-        // Bubble bar is pinned to the same side per gravity and the desired location.
-        // Resting translation does not need to be adjusted.
-        if (locationOnLeft == gravityOnLeft) {
-            return;
-        }
-
+    public PointF getBubbleBarDragReleaseTranslation(PointF initialTranslation,
+            BubbleBarLocation location) {
+        // Start with the initial translation. Value on y-axis can be reused.
+        final PointF dragEndTranslation = new PointF(initialTranslation);
         // Bubble bar is laid out on left or right side of the screen. And the desired new
-        // location is on the other side. Calculate x translation value required to shift the
+        // location is on the other side. Calculate x translation value required to shift
         // bubble bar from one side to the other.
-        float x = getDistanceFromOtherSide();
-        if (locationOnLeft) {
+        final float shift = getDistanceFromOtherSide();
+        if (location.isOnLeft(isLayoutRtl())) {
             // New location is on the left, shift left
             // before -> |......ooo.| after -> |.ooo......|
-            restingPosition.x = -x;
+            dragEndTranslation.x = -shift;
         } else {
             // New location is on the right, shift right
             // before -> |.ooo......| after -> |......ooo.|
-            restingPosition.x = x;
+            dragEndTranslation.x = shift;
         }
+        return dragEndTranslation;
+    }
+
+    /**
+     * Get translation for a bubble when drag is released and it needs to animate back to the
+     * resting position.
+     * Resting position is based on the supplied location. If the supplied location is different
+     * from the internal location that was used during bubble bar layout, translation values are
+     * calculated to position the bar at the desired location.
+     *
+     * @param initialTranslation initial bubble bar translation at the start of drag
+     * @param location           desired location of the bubble bar when drag is released
+     * @return point with x and y values representing translation on x and y-axis
+     */
+    public PointF getDraggedBubbleReleaseTranslation(PointF initialTranslation,
+            BubbleBarLocation location) {
+        // Start with bubble bar translation
+        final PointF dragEndTranslation = new PointF(
+                getBubbleBarDragReleaseTranslation(initialTranslation, location));
+        // Apply individual bubble translation, as the order may have changed
+        int viewIndex = indexOfChild(mDraggedBubbleView);
+        dragEndTranslation.x += getExpandedBubbleTranslationX(viewIndex,
+                getChildCount(),
+                location.isOnLeft(isLayoutRtl()));
+        return dragEndTranslation;
     }
 
     private float getDistanceFromOtherSide() {
@@ -345,55 +419,46 @@
         return (float) (displayWidth - getWidth() - margin);
     }
 
-    private void setBubbleBarLocationInternal(BubbleBarLocation bubbleBarLocation) {
-        if (bubbleBarLocation != mBubbleBarLocation) {
-            mBubbleBarLocation = bubbleBarLocation;
-            if (mDragging) {
-                mLocationChangePending = true;
-            } else {
-                onBubbleBarLocationChanged();
-                invalidate();
-            }
-        }
-    }
-
-    private void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
-        if (bubbleBarLocation == mBubbleBarLocation) {
-            // nothing to do, already at expected location
-            return;
-        }
+    /**
+     * Animate bubble bar to the given location transiently. Does not modify the layout or the value
+     * returned by {@link #getBubbleBarLocation()}.
+     */
+    public void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
         if (mBubbleBarLocationAnimator != null && mBubbleBarLocationAnimator.isRunning()) {
+            mBubbleBarLocationAnimator.removeAllListeners();
             mBubbleBarLocationAnimator.cancel();
         }
 
         // Location animation uses two separate animators.
         // First animator hides the bar.
-        // After it completes, location update is sent to layout the bar in the new location.
+        // After it completes, bubble positions in the bar and arrow position is updated.
         // Second animator is started to show the bar.
-        mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator();
+        mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator(bubbleBarLocation);
         mBubbleBarLocationAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                // Bubble bar is not visible, update the location
-                setBubbleBarLocationInternal(bubbleBarLocation);
+                updateChildrenRenderNodeProperties(bubbleBarLocation);
+                mBubbleBarBackground.setAnchorLeft(bubbleBarLocation.isOnLeft(isLayoutRtl()));
+
                 // Animate it in
-                mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator();
+                mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator(bubbleBarLocation);
                 mBubbleBarLocationAnimator.start();
             }
         });
         mBubbleBarLocationAnimator.start();
     }
 
-    private AnimatorSet getLocationUpdateFadeOutAnimator() {
+    private Animator getLocationUpdateFadeOutAnimator(BubbleBarLocation newLocation) {
         final float shift =
                 getResources().getDisplayMetrics().widthPixels * FADE_OUT_ANIM_POSITION_SHIFT;
-        final float tx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+        final boolean onLeft = newLocation.isOnLeft(isLayoutRtl());
+        final float tx = getTranslationX() + (onLeft ? -shift : shift);
 
-        ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X, tx)
+        ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, VIEW_TRANSLATE_X, tx)
                 .setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS);
         positionAnim.setInterpolator(EMPHASIZED_ACCELERATE);
 
-        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 0f)
+        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 0f)
                 .setDuration(FADE_OUT_ANIM_ALPHA_DURATION_MS);
         alphaAnim.setStartDelay(FADE_OUT_ANIM_ALPHA_DELAY_MS);
 
@@ -402,19 +467,36 @@
         return animatorSet;
     }
 
-    private Animator getLocationUpdateFadeInAnimator() {
+    private Animator getLocationUpdateFadeInAnimator(BubbleBarLocation newLocation) {
         final float shift =
                 getResources().getDisplayMetrics().widthPixels * FADE_IN_ANIM_POSITION_SHIFT;
-        final float startTx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+
+        final boolean onLeft = newLocation.isOnLeft(isLayoutRtl());
+        final float startTx;
+        final float finalTx;
+        if (newLocation == mBubbleBarLocation) {
+            // Animated location matches layout location.
+            finalTx = 0;
+        } else {
+            // We are animating in to a transient location, need to move the bar accordingly.
+            finalTx = getDistanceFromOtherSide() * (onLeft ? -1 : 1);
+        }
+        if (onLeft) {
+            // Bar will be shown on the left side. Start point is shifted right.
+            startTx = finalTx + shift;
+        } else {
+            // Bar will be shown on the right side. Start point is shifted left.
+            startTx = finalTx - shift;
+        }
 
         ValueAnimator positionAnim = new SpringAnimationBuilder(getContext())
                 .setStartValue(startTx)
-                .setEndValue(0)
+                .setEndValue(finalTx)
                 .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
                 .setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
                 .build(this, VIEW_TRANSLATE_X);
 
-        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 1f)
+        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 1f)
                 .setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
 
         AnimatorSet animatorSet = new AnimatorSet();
@@ -423,6 +505,49 @@
     }
 
     /**
+     * Get property that can be used to animate the alpha value for the bar.
+     * When a bubble is being dragged, uses {@link #BUBBLE_DRAG_ALPHA}.
+     * Falls back to {@link com.android.launcher3.LauncherAnimUtils#VIEW_ALPHA} otherwise.
+     */
+    private FloatProperty<? super BubbleBarView> getLocationAnimAlphaProperty() {
+        return mDraggedBubbleView == null ? VIEW_ALPHA : BUBBLE_DRAG_ALPHA;
+    }
+
+    /**
+     * Set alpha value for the bar while a bubble is being dragged.
+     * We can not update the alpha on the bar directly because the dragged bubble would be affected
+     * as well. As it is a child view.
+     * Instead, while a bubble is being dragged, set alpha on each child view, that is not the
+     * dragged view. And set an alpha on the background.
+     * This allows for the dragged bubble to remain visible while the bar is hidden during
+     * animation.
+     */
+    private void setAlphaDuringBubbleDrag(float alpha) {
+        mAlphaDuringDrag = alpha;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View view = getChildAt(i);
+            if (view != mDraggedBubbleView) {
+                view.setAlpha(alpha);
+            }
+        }
+        if (mBubbleBarBackground != null) {
+            mBubbleBarBackground.setAlpha((int) (255 * alpha));
+        }
+    }
+
+    private void resetDragAnimation() {
+        if (mBubbleBarLocationAnimator != null) {
+            mBubbleBarLocationAnimator.removeAllListeners();
+            mBubbleBarLocationAnimator.cancel();
+            mBubbleBarLocationAnimator = null;
+        }
+        setAlphaDuringBubbleDrag(1f);
+        setTranslationX(0f);
+        setAlpha(1f);
+    }
+
+    /**
      * Updates the bounds with translation that may have been applied and returns the result.
      */
     public Rect getBubbleBarBounds() {
@@ -443,6 +568,11 @@
         requestLayout();
     }
 
+    /** Like {@link #setRelativePivot(float, float)} but only updates pivot y. */
+    public void setRelativePivotY(float y) {
+        setRelativePivot(mRelativePivotX, y);
+    }
+
     /**
      * Get current relative pivot for X axis
      */
@@ -457,38 +587,14 @@
         return mRelativePivotY;
     }
 
-    /** Prepares for animating a bubble while being stashed. */
-    public void prepareForAnimatingBubbleWhileStashed(String bubbleKey) {
+    /** Notifies the bubble bar that a new bubble animation is starting. */
+    public void onAnimatingBubbleStarted() {
         mIsAnimatingNewBubble = true;
-        // we're about to animate the new bubble in. the new bubble has already been added to this
-        // view, but we're currently stashed, so before we can start the animation we need make
-        // everything else in the bubble bar invisible, except for the bubble that's being animated.
-        setBackground(null);
-        for (int i = 0; i < getChildCount(); i++) {
-            final BubbleView view = (BubbleView) getChildAt(i);
-            final String key = view.getBubble().getKey();
-            if (!bubbleKey.equals(key)) {
-                view.setVisibility(INVISIBLE);
-            }
-        }
-        setVisibility(VISIBLE);
-        setAlpha(1);
-        setTranslationY(0);
-        setScaleX(1);
-        setScaleY(1);
     }
 
-    /** Resets the state after the bubble animation completed. */
+    /** Notifies the bubble bar that a new bubble animation is complete. */
     public void onAnimatingBubbleCompleted() {
         mIsAnimatingNewBubble = false;
-        // setting the background triggers relayout so no need to explicitly invalidate after the
-        // animation
-        setBackground(mBubbleBarBackground);
-        for (int i = 0; i < getChildCount(); i++) {
-            final BubbleView view = (BubbleView) getChildAt(i);
-            view.setVisibility(VISIBLE);
-            view.setAlpha(1f);
-        }
     }
 
     // TODO: (b/280605790) animate it
@@ -507,6 +613,10 @@
     @Override
     public void removeView(View view) {
         super.removeView(view);
+        if (view == mSelectedBubbleView) {
+            mSelectedBubbleView = null;
+            mBubbleBarBackground.showArrow(false);
+        }
         updateWidth();
     }
 
@@ -516,6 +626,13 @@
         setLayoutParams(lp);
     }
 
+    private void updateLayoutParams() {
+        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        lp.height = (int) getBubbleBarExpandedHeight();
+        lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
+        setLayoutParams(lp);
+    }
+
     /** @return the horizontal margin between the bubble bar and the edge of the screen. */
     int getHorizontalMargin() {
         LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -526,13 +643,7 @@
      * Updates the z order, positions, and badge visibility of the bubble views in the bar based
      * on the expanded state.
      */
-    private void updateChildrenRenderNodeProperties() {
-        if (mIsAnimatingNewBubble) {
-            // don't update bubbles if a new bubble animation is playing.
-            // the bubble bar will redraw itself via onLayout after the animation.
-            return;
-        }
-
+    private void updateChildrenRenderNodeProperties(BubbleBarLocation bubbleBarLocation) {
         final float widthState = (float) mWidthAnimator.getAnimatedValue();
         final float currentWidth = getWidth();
         final float expandedWidth = expandedWidth();
@@ -540,25 +651,29 @@
         int bubbleCount = getChildCount();
         final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
         final boolean animate = getVisibility() == VISIBLE;
-        final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
+        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++) {
             BubbleView bv = (BubbleView) getChildAt(i);
+            if (bv == mDraggedBubbleView) {
+                // Skip the dragged bubble. Its translation is managed by the drag controller.
+                continue;
+            }
+            // Clear out drag translation and offset
+            bv.setDragTranslationX(0f);
+            bv.setOffsetX(0f);
+
             bv.setTranslationY(ty);
 
             // the position of the bubble when the bar is fully expanded
-            final float expandedX;
+            final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
             // the position of the bubble when the bar is fully collapsed
-            final float collapsedX;
-            if (onLeft) {
-                // If bar is on the left, bubbles are ordered right to left
-                expandedX = (bubbleCount - i - 1) * (mIconSize + mIconSpacing);
-                // Shift the first bubble only if there are more bubbles in addition to overflow
-                collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0;
-            } else {
-                // Bubbles ordered left to right, don't move the first bubble
-                expandedX = i * (mIconSize + mIconSpacing);
-                collapsedX = i == 0 ? 0 : mIconOverlapAmount;
-            }
+            final float collapsedX = getCollapsedBubbleTranslationX(i, bubbleCount, onLeft);
+
+            // slowly animate elevation while keeping correct Z ordering
+            float fullElevationForChild = (MAX_BUBBLES * mBubbleElevation) - i;
+            bv.setZ(fullElevationForChild * elevationState);
 
             if (mIsBarExpanded) {
                 // If bar is on the right, account for bubble bar expanding and shifting left
@@ -566,10 +681,6 @@
                 // where the bubble will end up when the animation ends
                 final float targetX = expandedX + expandedBarShift;
                 bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
-                // if we're fully expanded, set the z level to 0 or to bubble elevation if dragged
-                if (widthState == 1f) {
-                    bv.setZ(bv == mDraggedBubbleView ? mBubbleElevation : 0);
-                }
                 // When we're expanded, we're not stacked so we're not behind the stack
                 bv.setBehindStack(false, animate);
                 bv.setAlpha(1);
@@ -578,15 +689,15 @@
                 final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
                 final float targetX = collapsedX + collapsedBarShift;
                 bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
-                bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
                 // If we're not the first bubble we're behind the stack
                 bv.setBehindStack(i > 0, animate);
                 // 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 (widthState == 0) {
-                    if (i > 1) {
+                    if (i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
                         bv.setAlpha(0);
-                    } else if (i == 1 && bubbleCount == 2) {
+                    } else if (i == MAX_VISIBLE_BUBBLES_COLLAPSED - 1
+                            && bubbleCount == MAX_VISIBLE_BUBBLES_COLLAPSED) {
                         bv.setAlpha(0);
                     }
                 }
@@ -594,19 +705,20 @@
         }
 
         // update the arrow position
-        final float collapsedArrowPosition = arrowPositionForSelectedWhenCollapsed();
-        final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded();
+        final float collapsedArrowPosition = arrowPositionForSelectedWhenCollapsed(
+                bubbleBarLocation);
+        final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded(bubbleBarLocation);
         final float interpolatedWidth =
                 widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
         final float arrowPosition;
+
+        float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
         if (onLeft) {
-            float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
             arrowPosition = collapsedArrowPosition + interpolatedShift;
         } else {
             if (mIsBarExpanded) {
-                // when the bar is expanding, the selected bubble is always the first, so the arrow
-                // always shifts with the interpolated width.
-                arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
+                arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition
+                        + interpolatedShift;
             } else {
                 final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
                 arrowPosition =
@@ -618,6 +730,34 @@
         mBubbleBarBackground.setWidth(interpolatedWidth);
     }
 
+    private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount,
+            boolean onLeft) {
+        if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+            return 0;
+        }
+        if (onLeft) {
+            // If bar is on the left, bubbles are ordered right to left
+            return (bubbleCount - bubbleIndex - 1) * (mIconSize + mExpandedBarIconsSpacing);
+        } else {
+            // Bubbles ordered left to right, don't move the first bubble
+            return bubbleIndex * (mIconSize + mExpandedBarIconsSpacing);
+        }
+    }
+
+    private float getCollapsedBubbleTranslationX(int bubbleIndex, int bubbleCount,
+            boolean onLeft) {
+        if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+            return 0;
+        }
+        if (onLeft) {
+            // Shift the first bubble only if there are more bubbles in addition to overflow
+            return bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
+                    ? mIconOverlapAmount : 0;
+        } else {
+            return bubbleIndex == 0 ? 0 : mIconOverlapAmount;
+        }
+    }
+
     /**
      * Reorders the views to match the provided list.
      */
@@ -642,7 +782,7 @@
                     addViewInLayout(child, i, child.getLayoutParams());
                 }
             }
-            updateChildrenRenderNodeProperties();
+            updateChildrenRenderNodeProperties(mBubbleBarLocation);
         }
     }
 
@@ -655,16 +795,26 @@
      * Sets which bubble view should be shown as selected.
      */
     public void setSelectedBubble(BubbleView view) {
+        BubbleView previouslySelectedBubble = mSelectedBubbleView;
         mSelectedBubbleView = view;
-        updateArrowForSelected(/* shouldAnimate= */ true);
+        mBubbleBarBackground.showArrow(view != null);
+        // TODO: (b/283309949) remove animation should be implemented first, so than arrow
+        //  animation is adjusted, skip animation for now
+        updateArrowForSelected(previouslySelectedBubble != null);
     }
 
     /**
      * Sets the dragged bubble view to correctly apply Z order. Dragged view should appear on top
      */
     public void setDraggedBubble(@Nullable BubbleView view) {
+        if (mDraggedBubbleView != null) {
+            mDraggedBubbleView.setZ(0);
+        }
         mDraggedBubbleView = view;
-        requestLayout();
+        if (view != null) {
+            view.setZ(mDragElevation);
+        }
+        setIsDragging(view != null);
     }
 
     /**
@@ -679,8 +829,12 @@
             return;
         }
         // Find the center of the bubble when it's expanded, set the arrow position to it.
-        final float tx = arrowPositionForSelectedWhenExpanded();
+        final float tx = arrowPositionForSelectedWhenExpanded(mBubbleBarLocation);
         final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
+        if (tx == currentArrowPosition) {
+            // arrow position remains unchanged
+            return;
+        }
         if (shouldAnimate && currentArrowPosition > expandedWidth()) {
             Log.d(TAG, "arrow out of bounds of expanded view, skip animation");
             shouldAnimate = false;
@@ -700,25 +854,26 @@
         }
     }
 
-    private float arrowPositionForSelectedWhenExpanded() {
+    private float arrowPositionForSelectedWhenExpanded(BubbleBarLocation bubbleBarLocation) {
         final int index = indexOfChild(mSelectedBubbleView);
         final int bubblePosition;
-        if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+        if (bubbleBarLocation.isOnLeft(isLayoutRtl())) {
             // Bubble positions are reversed. First bubble is on the right.
             bubblePosition = getChildCount() - index - 1;
         } else {
             bubblePosition = index;
         }
-        return getPaddingStart() + bubblePosition * (mIconSize + mIconSpacing) + mIconSize / 2f;
+        return getPaddingStart() + bubblePosition * (mIconSize + mExpandedBarIconsSpacing)
+                + mIconSize / 2f;
     }
 
-    private float arrowPositionForSelectedWhenCollapsed() {
+    private float arrowPositionForSelectedWhenCollapsed(BubbleBarLocation bubbleBarLocation) {
         final int index = indexOfChild(mSelectedBubbleView);
         final int bubblePosition;
-        if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+        if (bubbleBarLocation.isOnLeft(isLayoutRtl())) {
             // Bubble positions are reversed. First bubble may be shifted, if there are more
             // bubbles than the current bubble and overflow.
-            bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0;
+            bubblePosition = index == 0 && getChildCount() > MAX_VISIBLE_BUBBLES_COLLAPSED ? 1 : 0;
         } else {
             bubblePosition = index;
         }
@@ -770,7 +925,9 @@
     public float expandedWidth() {
         final int childCount = getChildCount();
         final int horizontalPadding = getPaddingStart() + getPaddingEnd();
-        return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
+        // spaces amount is less than child count by 1, or 0 if no child views
+        int spacesCount = Math.max(childCount - 1, 0);
+        return childCount * mIconSize + spacesCount * mExpandedBarIconsSpacing + horizontalPadding;
     }
 
     private float collapsedWidth() {
@@ -778,11 +935,20 @@
         final int horizontalPadding = getPaddingStart() + getPaddingEnd();
         // 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 > 2
+        return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
                 ? mIconSize + mIconOverlapAmount + horizontalPadding
                 : mIconSize + horizontalPadding;
     }
 
+    private float getBubbleBarExpandedHeight() {
+        return getBubbleBarCollapsedHeight() + mPointerSize;
+    }
+
+    float getBubbleBarCollapsedHeight() {
+        // the pointer is invisible when collapsed
+        return mIconSize + mBubbleBarPadding * 2;
+    }
+
     /**
      * Returns whether the given MotionEvent, *in screen coordinates*, is within bubble bar
      * touch bounds.
@@ -797,10 +963,15 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (!mIsBarExpanded) {
+        if (!mIsBarExpanded && !mIsAnimatingNewBubble) {
             // When the bar is collapsed, all taps on it should expand it.
             return true;
         }
         return super.onInterceptTouchEvent(ev);
     }
+
+    /** Whether a new bubble is currently animating. */
+    public boolean isAnimatingNewBubble() {
+        return mIsAnimatingNewBubble;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index aa1b4df..cd8eaf9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,9 +18,13 @@
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 
+import android.content.res.Resources;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
+import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -51,13 +55,14 @@
  */
 public class BubbleBarViewController {
 
-    private static final String TAG = BubbleBarViewController.class.getSimpleName();
-
+    private static final String TAG = "BubbleBarViewController";
+    private static final float APP_ICON_SMALL_DP = 44f;
+    private static final float APP_ICON_MEDIUM_DP = 48f;
+    private static final float APP_ICON_LARGE_DP = 52f;
     private final SystemUiProxy mSystemUiProxy;
     private final TaskbarActivityContext mActivity;
     private final BubbleBarView mBarView;
-    private final int mIconSize;
-    private final int mPointerSize;
+    private int mIconSize;
 
     // Initialized in init.
     private BubbleStashController mBubbleStashController;
@@ -96,9 +101,8 @@
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
         mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
         mBubbleBarAlpha.setUpdateVisibility(true);
-        mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
-        mPointerSize = activity.getResources().getDimensionPixelSize(
-                R.dimen.bubblebar_pointer_size);
+        mIconSize = activity.getResources().getDimensionPixelSize(
+                R.dimen.bubblebar_icon_size);
     }
 
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -108,12 +112,8 @@
         mTaskbarStashController = controllers.taskbarStashController;
         mTaskbarInsetsController = controllers.taskbarInsetsController;
 
-        mActivity.addOnDeviceProfileChangeListener(dp ->
-                mBarView.getLayoutParams().height =
-                        mActivity.getDeviceProfile().taskbarHeight + mPointerSize
-        );
-        mBarView.getLayoutParams().height =
-                mActivity.getDeviceProfile().taskbarHeight + mPointerSize;
+        mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
+        setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
         mBubbleBarScale.updateValue(1f);
         mBubbleClickListener = v -> onBubbleClicked(v);
         mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -139,6 +139,15 @@
         if (bubble == null) {
             Log.e(TAG, "bubble click listener, bubble was null");
         }
+
+        if (mBarView.isAnimatingNewBubble()) {
+            mBubbleBarViewAnimator.onBubbleClickedWhileAnimating();
+            mBubbleStashController.showBubbleBarImmediate();
+            setExpanded(true);
+            mBubbleBarController.showAndSelectBubble(bubble);
+            return;
+        }
+
         final String currentlySelected = mBubbleBarController.getSelectedBubbleKey();
         if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) {
             // Tapping the currently selected bubble while expanded collapses the view.
@@ -164,6 +173,13 @@
         }
     }
 
+    /** Notifies that the stash state is changing. */
+    public void onStashStateChanging() {
+        if (isAnimatingNewBubble()) {
+            mBubbleBarViewAnimator.onStashStateChangingWhileAnimating();
+        }
+    }
+
     //
     // The below animators are exposed to BubbleStashController so it can manage the stashing
     // animation.
@@ -181,6 +197,10 @@
         return mBubbleBarTranslationY;
     }
 
+    float getBubbleBarCollapsedHeight() {
+        return mBarView.getBubbleBarCollapsedHeight();
+    }
+
     /**
      * Whether the bubble bar is visible or not.
      */
@@ -203,8 +223,17 @@
     /**
      * Update bar {@link BubbleBarLocation}
      */
-    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
-        mBarView.setBubbleBarLocation(bubbleBarLocation, animate);
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        mBarView.setBubbleBarLocation(bubbleBarLocation);
+    }
+
+    /**
+     * Animate bubble bar to the given location. The location change is transient. It does not
+     * update the state of the bubble bar.
+     * To update bubble bar pinned location, use {@link #setBubbleBarLocation(BubbleBarLocation)}.
+     */
+    public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        mBarView.animateToBubbleBarLocation(bubbleBarLocation);
     }
 
     /**
@@ -214,6 +243,11 @@
         return mBarView.getBubbleBarBounds();
     }
 
+    /** Whether a new bubble is animating. */
+    public boolean isAnimatingNewBubble() {
+        return mBarView.isAnimatingNewBubble();
+    }
+
     /** The horizontal margin of the bubble bar from the edge of the screen. */
     public int getHorizontalMargin() {
         return mBarView.getHorizontalMargin();
@@ -260,12 +294,44 @@
         }
     }
 
+    private void setBubbleBarIconSize(int newIconSize) {
+        if (newIconSize == mIconSize) {
+            return;
+        }
+        Resources res = mActivity.getResources();
+        DisplayMetrics dm = res.getDisplayMetrics();
+        float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_SMALL_DP, dm);
+        float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_MEDIUM_DP, dm);
+        float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_LARGE_DP, dm);
+        float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
+        float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
+        mIconSize = newIconSize <= smallMediumThreshold
+                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
+                res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+        float bubbleBarPadding = newIconSize >= mediumLargeThreshold
+                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
+                res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+
+        mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
+        mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
+                (int) bubbleBarPadding,
+                mBarView.getPaddingBottom());
+    }
+
     /** Sets a callback that updates the selected bubble after the bubble bar collapses. */
     public void setUpdateSelectedBubbleAfterCollapse(
             Consumer<String> updateSelectedBubbleAfterCollapse) {
         mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
     }
 
+    /** Returns whether the bubble bar should be hidden because of the current sysui state. */
+    boolean isHiddenForSysui() {
+        return mHiddenForSysui;
+    }
+
     /**
      * Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
      */
@@ -340,11 +406,21 @@
                 return;
             }
 
-            boolean isStashedOrGone =
-                    mBubbleStashController.isStashed() || mBarView.getVisibility() != VISIBLE;
-            // don't animate the new bubble if we're auto expanding from stashed
-            if (b instanceof BubbleBarBubble && isStashedOrGone && !isExpanding) {
-                mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
+            if (!(b instanceof BubbleBarBubble bubble)) {
+                return;
+            }
+
+            boolean isInApp = mTaskbarStashController.isInApp();
+            // if this is the first bubble, animate to the initial state. one bubble is the overflow
+            // so check for at most 2 children.
+            if (mBarView.getChildCount() <= 2) {
+                mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
+                return;
+            }
+
+            // only animate the new bubble if we're in an app and not auto expanding
+            if (isInApp && !isExpanding && !isExpanded()) {
+                mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
             }
         } else {
             Log.w(TAG, "addBubble, bubble was null!");
@@ -411,7 +487,8 @@
      */
     public void onDragStart(@NonNull BubbleView bubbleView) {
         if (bubbleView.getBubble() == null) return;
-        mSystemUiProxy.onBubbleDrag(bubbleView.getBubble().getKey(), /* isBeingDragged = */ true);
+
+        mSystemUiProxy.startBubbleDrag(bubbleView.getBubble().getKey());
         mBarView.setDraggedBubble(bubbleView);
     }
 
@@ -419,19 +496,46 @@
      * Notifies SystemUI to expand the selected bubble when the bubble is released.
      * @param bubbleView dragged bubble view
      */
-    public void onDragRelease(@NonNull BubbleView bubbleView) {
+    public void onDragRelease(@NonNull BubbleView bubbleView, BubbleBarLocation location) {
         if (bubbleView.getBubble() == null) return;
-        mSystemUiProxy.onBubbleDrag(bubbleView.getBubble().getKey(), /* isBeingDragged = */ false);
+        // TODO(b/330585402): send new bubble bar bounds to shell for the animation
+        mSystemUiProxy.stopBubbleDrag(bubbleView.getBubble().getKey(), location);
     }
 
     /**
-     * Removes the dragged bubble view in the bubble bar view
+     * Notifies {@link BubbleBarView} that drag and all animations are finished.
      */
     public void onDragEnd() {
         mBarView.setDraggedBubble(null);
     }
 
     /**
+     * Get translation for bubble bar when drag is released.
+     *
+     * @see BubbleBarView#getBubbleBarDragReleaseTranslation(PointF, BubbleBarLocation)
+     */
+    public PointF getBubbleBarDragReleaseTranslation(PointF initialTranslation,
+            BubbleBarLocation location) {
+        if (location == mBarView.getBubbleBarLocation()) {
+            return initialTranslation;
+        }
+        return mBarView.getBubbleBarDragReleaseTranslation(initialTranslation, location);
+    }
+
+    /**
+     * Get translation for bubble view when drag is released.
+     *
+     * @see BubbleBarView#getDraggedBubbleReleaseTranslation(PointF, BubbleBarLocation)
+     */
+    public PointF getDraggedBubbleReleaseTranslation(PointF initialTranslation,
+            BubbleBarLocation location) {
+        if (location == mBarView.getBubbleBarLocation()) {
+            return initialTranslation;
+        }
+        return mBarView.getDraggedBubbleReleaseTranslation(initialTranslation, location);
+    }
+
+    /**
      * Called when bubble was dragged into the dismiss target. Notifies System
      * @param bubble dismissed bubble item
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index 90f1be3..295477c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -30,6 +30,7 @@
     public final BubbleDragController bubbleDragController;
     public final BubbleDismissController bubbleDismissController;
     public final BubbleBarPinController bubbleBarPinController;
+    public final BubblePinController bubblePinController;
 
     private final RunnableList mPostInitRunnables = new RunnableList();
 
@@ -45,7 +46,8 @@
             BubbleStashedHandleViewController bubbleStashedHandleViewController,
             BubbleDragController bubbleDragController,
             BubbleDismissController bubbleDismissController,
-            BubbleBarPinController bubbleBarPinController) {
+            BubbleBarPinController bubbleBarPinController,
+            BubblePinController bubblePinController) {
         this.bubbleBarController = bubbleBarController;
         this.bubbleBarViewController = bubbleBarViewController;
         this.bubbleStashController = bubbleStashController;
@@ -53,6 +55,7 @@
         this.bubbleDragController = bubbleDragController;
         this.bubbleDismissController = bubbleDismissController;
         this.bubbleBarPinController = bubbleBarPinController;
+        this.bubblePinController = bubblePinController;
     }
 
     /**
@@ -68,6 +71,7 @@
         bubbleDragController.init(/* bubbleControllers = */ this);
         bubbleDismissController.init(/* bubbleControllers = */ this);
         bubbleBarPinController.init(this);
+        bubblePinController.init(this);
 
         mPostInitRunnables.executeAllAndDestroy();
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index a40f33c..0e6fa3c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -40,7 +40,7 @@
  * @see BubbleDragController
  */
 public class BubbleDismissController {
-    private static final String TAG = BubbleDismissController.class.getSimpleName();
+    private static final String TAG = "BubbleDismissController";
     private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
     private final TaskbarActivityContext mActivity;
     private final TaskbarDragLayer mDragLayer;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 8b811d9..287e906 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -60,6 +60,7 @@
     private final float mBubbleFocusedScale;
     private final float mBubbleCapturedScale;
     private final float mDismissCapturedScale;
+    private final FloatPropertyCompat<View> mTranslationXProperty;
 
     /**
      * Should be initialised for each dragged view
@@ -81,9 +82,28 @@
         if (view instanceof BubbleBarView) {
             mBubbleFocusedScale = SCALE_BUBBLE_BAR_FOCUSED;
             mBubbleCapturedScale = mDismissCapturedScale;
+            mTranslationXProperty = DynamicAnimation.TRANSLATION_X;
         } else {
             mBubbleFocusedScale = SCALE_BUBBLE_FOCUSED;
             mBubbleCapturedScale = SCALE_BUBBLE_CAPTURED;
+            // Wrap BubbleView.DRAG_TRANSLATION_X as it can't be cast to FloatPropertyCompat<View>
+            mTranslationXProperty = new FloatPropertyCompat<>(
+                    BubbleView.DRAG_TRANSLATION_X.getName()) {
+                @Override
+                public float getValue(View object) {
+                    if (object instanceof BubbleView bubbleView) {
+                        return BubbleView.DRAG_TRANSLATION_X.get(bubbleView);
+                    }
+                    return 0;
+                }
+
+                @Override
+                public void setValue(View object, float value) {
+                    if (object instanceof BubbleView bubbleView) {
+                        BubbleView.DRAG_TRANSLATION_X.setValue(bubbleView, value);
+                    }
+                }
+            };
         }
     }
 
@@ -110,25 +130,25 @@
     /**
      * Animates the dragged bubble movement back to the initial position.
      *
-     * @param initialPosition the position to animate to
+     * @param restingPosition the position to animate to
      * @param velocity        the initial velocity to use for the spring animation
      * @param endActions      gets called when the animation completes or gets cancelled
      */
-    public void animateToInitialState(@NonNull PointF initialPosition, @NonNull PointF velocity,
+    public void animateToRestingState(@NonNull PointF restingPosition, @NonNull PointF velocity,
             @Nullable Runnable endActions) {
         mBubbleAnimator.cancel();
         mBubbleAnimator
                 .spring(DynamicAnimation.SCALE_X, 1f)
                 .spring(DynamicAnimation.SCALE_Y, 1f)
-                .spring(DynamicAnimation.TRANSLATION_X, initialPosition.x, velocity.x,
+                .spring(mTranslationXProperty, restingPosition.x, velocity.x,
                         mTranslationConfig)
-                .spring(DynamicAnimation.TRANSLATION_Y, initialPosition.y, velocity.y,
+                .spring(DynamicAnimation.TRANSLATION_Y, restingPosition.y, velocity.y,
                         mTranslationConfig)
                 .addEndListener((View target, @NonNull FloatPropertyCompat<? super View> property,
                         boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
                         boolean allRelevantPropertyAnimationsEnded) -> {
                     if (canceled || allRelevantPropertyAnimationsEnded) {
-                        resetAnimatedViews(initialPosition);
+                        resetAnimatedViews(restingPosition);
                         if (endActions != null) {
                             endActions.run();
                         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 5ffc6d8..15de1b8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -26,6 +26,8 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
 
 /**
  * Controls bubble bar drag interactions.
@@ -37,9 +39,11 @@
  */
 public class BubbleDragController {
     private final TaskbarActivityContext mActivity;
+    private BubbleBarController mBubbleBarController;
     private BubbleBarViewController mBubbleBarViewController;
     private BubbleDismissController mBubbleDismissController;
     private BubbleBarPinController mBubbleBarPinController;
+    private BubblePinController mBubblePinController;
 
     public BubbleDragController(TaskbarActivityContext activity) {
         mActivity = activity;
@@ -51,13 +55,16 @@
      * controllers may still be waiting for init().
      */
     public void init(@NonNull BubbleControllers bubbleControllers) {
+        mBubbleBarController = bubbleControllers.bubbleBarController;
         mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
         mBubbleDismissController = bubbleControllers.bubbleDismissController;
         mBubbleBarPinController = bubbleControllers.bubbleBarPinController;
-        mBubbleBarPinController.setListener(
-                bubbleControllers.bubbleBarController::updateBubbleBarLocation);
+        mBubblePinController = bubbleControllers.bubblePinController;
         mBubbleDismissController.setListener(
-                stuck -> mBubbleBarPinController.setDropTargetHidden(stuck));
+                stuck -> {
+                    mBubbleBarPinController.setDropTargetHidden(stuck);
+                    mBubblePinController.setDropTargetHidden(stuck);
+                });
     }
 
     /**
@@ -71,19 +78,60 @@
         }
 
         bubbleView.setOnTouchListener(new BubbleTouchListener() {
+
+            private BubbleBarLocation mReleasedLocation = BubbleBarLocation.DEFAULT;
+
+            private final LocationChangeListener mLocationChangeListener =
+                    new LocationChangeListener() {
+                        @Override
+                        public void onChange(@NonNull BubbleBarLocation location) {
+                            mBubbleBarController.animateBubbleBarLocation(location);
+                        }
+
+                        @Override
+                        public void onRelease(@NonNull BubbleBarLocation location) {
+                            mReleasedLocation = location;
+                        }
+                    };
+
             @Override
             void onDragStart() {
+                mBubblePinController.setListener(mLocationChangeListener);
                 mBubbleBarViewController.onDragStart(bubbleView);
+                mBubblePinController.onDragStart(
+                        mBubbleBarViewController.getBubbleBarLocation().isOnLeft(
+                                bubbleView.isLayoutRtl()));
             }
 
             @Override
-            void onDragEnd() {
-                mBubbleBarViewController.onDragEnd();
+            protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+                bubbleView.setDragTranslationX(newTx);
+                bubbleView.setTranslationY(newTy);
+                mBubblePinController.onDragUpdate(x, y);
             }
 
             @Override
             protected void onDragRelease() {
-                mBubbleBarViewController.onDragRelease(bubbleView);
+                mBubblePinController.onDragEnd();
+                mBubbleBarViewController.onDragRelease(bubbleView, mReleasedLocation);
+            }
+
+            @Override
+            protected void onDragDismiss() {
+                mBubblePinController.onDragEnd();
+            }
+
+            @Override
+            void onDragEnd() {
+                mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+                mBubbleBarViewController.onDragEnd();
+                mBubblePinController.setListener(null);
+            }
+
+            @Override
+            protected PointF getRestingPosition() {
+                return mBubbleBarViewController.getDraggedBubbleReleaseTranslation(
+                        getInitialPosition(), mReleasedLocation);
             }
         });
     }
@@ -96,6 +144,11 @@
         PointF initialRelativePivot = new PointF();
         bubbleBarView.setOnTouchListener(new BubbleTouchListener() {
 
+            private BubbleBarLocation mReleasedLocation = BubbleBarLocation.DEFAULT;
+
+            private final LocationChangeListener mLocationChangeListener =
+                    location -> mReleasedLocation = location;
+
             @Override
             protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) {
                 if (bubbleBarView.isExpanded()) return false;
@@ -104,6 +157,7 @@
 
             @Override
             void onDragStart() {
+                mBubbleBarPinController.setListener(mLocationChangeListener);
                 initialRelativePivot.set(bubbleBarView.getRelativePivotX(),
                         bubbleBarView.getRelativePivotY());
                 // By default the bubble bar view pivot is in bottom right corner, while dragging
@@ -115,7 +169,9 @@
             }
 
             @Override
-            protected void onDragUpdate(float x, float y) {
+            protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+                bubbleBarView.setTranslationX(newTx);
+                bubbleBarView.setTranslationY(newTy);
                 mBubbleBarPinController.onDragUpdate(x, y);
             }
 
@@ -131,16 +187,18 @@
 
             @Override
             void onDragEnd() {
+                // Make sure to update location as the first thing. Pivot update causes a relayout
+                mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+                bubbleBarView.setIsDragging(false);
                 // Restoring the initial pivot for the bubble bar view
                 bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
-                bubbleBarView.setIsDragging(false);
+                mBubbleBarPinController.setListener(null);
             }
 
             @Override
             protected PointF getRestingPosition() {
-                PointF restingPosition = super.getRestingPosition();
-                bubbleBarView.adjustRelativeRestingPosition(restingPosition);
-                return restingPosition;
+                return mBubbleBarViewController.getBubbleBarDragReleaseTranslation(
+                        getInitialPosition(), mReleasedLocation);
             }
         });
     }
@@ -206,8 +264,7 @@
          * Called when bubble is dragged to new coordinates.
          * Not called while bubble is stuck to the dismiss target.
          */
-        protected void onDragUpdate(float x, float y) {
-        }
+        protected abstract void onDragUpdate(float x, float y, float newTx, float newTy);
 
         /**
          * Called when the dragging interaction has ended and all the animations have completed
@@ -229,6 +286,13 @@
         }
 
         /**
+         * Get the initial position of the view when drag started
+         */
+        protected PointF getInitialPosition() {
+            return mViewInitialPosition;
+        }
+
+        /**
          * Get the resting position of the view when drag is released
          */
         protected PointF getRestingPosition() {
@@ -345,9 +409,9 @@
         private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy,
                 float x, float y) {
             if (mBubbleDismissController.handleTouchEvent(event)) return;
-            view.setTranslationX(mViewInitialPosition.x + dx);
-            view.setTranslationY(mViewInitialPosition.y + dy);
-            onDragUpdate(x, y);
+            final float newTx = mViewInitialPosition.x + dx;
+            final float newTy = mViewInitialPosition.y + dy;
+            onDragUpdate(x, y, newTx, newTy);
         }
 
         private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
@@ -362,7 +426,7 @@
                 mAnimator.animateDismiss(mViewInitialPosition, onComplete);
             } else {
                 onDragRelease();
-                mAnimator.animateToInitialState(getRestingPosition(), getCurrentVelocity(),
+                mAnimator.animateToRestingState(getRestingPosition(), getCurrentVelocity(),
                         onComplete);
             }
             mBubbleDismissController.hideDismissView();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
new file mode 100644
index 0000000..a77e685
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Point
+import android.view.Gravity.BOTTOM
+import android.view.Gravity.LEFT
+import android.view.Gravity.RIGHT
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.R
+import com.android.wm.shell.common.bubbles.BaseBubblePinController
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+
+/** Controller to manage pinning bubble bar to left or right when dragging starts from a bubble */
+class BubblePinController(
+    private val context: Context,
+    private val container: FrameLayout,
+    screenSizeProvider: () -> Point
+) : BaseBubblePinController(screenSizeProvider) {
+
+    var dropTargetSize: Point? = null
+
+    private lateinit var bubbleBarViewController: BubbleBarViewController
+    private lateinit var bubbleStashController: BubbleStashController
+    private var exclRectWidth: Float = 0f
+    private var exclRectHeight: Float = 0f
+
+    private var dropTargetView: View? = null
+    // Fallback width and height in case shell has not sent the size over
+    private var dropTargetDefaultWidth: Int = 0
+    private var dropTargetDefaultHeight: Int = 0
+    private var dropTargetMargin: Int = 0
+
+    fun init(bubbleControllers: BubbleControllers) {
+        bubbleBarViewController = bubbleControllers.bubbleBarViewController
+        bubbleStashController = bubbleControllers.bubbleStashController
+        exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width)
+        exclRectHeight = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
+        dropTargetDefaultWidth =
+            context.resources.getDimensionPixelSize(
+                R.dimen.bubble_expanded_view_drop_target_default_width
+            )
+        dropTargetDefaultHeight =
+            context.resources.getDimensionPixelSize(
+                R.dimen.bubble_expanded_view_drop_target_default_height
+            )
+        dropTargetMargin =
+            context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_drop_target_margin)
+    }
+
+    override fun getExclusionRectWidth(): Float {
+        return exclRectWidth
+    }
+
+    override fun getExclusionRectHeight(): Float {
+        return exclRectHeight
+    }
+
+    override fun getDropTargetView(): View? {
+        return dropTargetView
+    }
+
+    override fun removeDropTargetView(view: View) {
+        container.removeView(view)
+        dropTargetView = null
+    }
+
+    override fun createDropTargetView(): View {
+        return LayoutInflater.from(context)
+            .inflate(R.layout.bubble_expanded_view_drop_target, container, false)
+            .also { view ->
+                dropTargetView = view
+                container.addView(view)
+            }
+    }
+
+    @SuppressLint("RtlHardcoded")
+    override fun updateLocation(location: BubbleBarLocation) {
+        val onLeft = location.isOnLeft(container.isLayoutRtl)
+
+        val bubbleBarBounds = bubbleBarViewController.bubbleBarBounds
+        dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> {
+            gravity = BOTTOM or (if (onLeft) LEFT else RIGHT)
+            width = dropTargetSize?.x ?: dropTargetDefaultWidth
+            height = dropTargetSize?.y ?: dropTargetDefaultHeight
+            bottomMargin =
+                -bubbleStashController.bubbleBarTranslationY.toInt() +
+                    bubbleBarBounds.height() +
+                    dropTargetMargin
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 61a2e22..5d01b9b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -23,7 +23,9 @@
 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;
@@ -32,6 +34,7 @@
 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;
 
 /**
  * Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
@@ -39,7 +42,7 @@
  */
 public class BubbleStashController {
 
-    private static final String TAG = BubbleStashController.class.getSimpleName();
+    private static final String TAG = "BubbleStashController";
 
     /**
      * How long to stash/unstash.
@@ -51,15 +54,6 @@
      */
     private static final float STASHED_BAR_SCALE = 0.5f;
 
-    /** The duration of hiding and showing the stashed handle as part of a new bubble animation. */
-    private static final long NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS = 200;
-
-    /** The translation Y value the handle animates to when hiding it for a new bubble. */
-    private static final int NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y = -20;
-
-    /** The alpha value the handle animates to when hiding it for a new bubble. */
-    public static final float NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA = 0.5f;
-
     protected final TaskbarActivityContext mActivity;
 
     // Initialized in init.
@@ -73,7 +67,6 @@
     private AnimatedFloat mIconScaleForStash;
     private AnimatedFloat mIconTranslationYForStash;
     private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
-    private AnimatedFloat mBubbleStashedHandleTranslationY;
 
     private boolean mRequestedStashState;
     private boolean mRequestedExpandedState;
@@ -85,11 +78,16 @@
     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) {
@@ -105,7 +103,6 @@
 
         mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
                 StashedHandleViewController.ALPHA_INDEX_STASHED);
-        mBubbleStashedHandleTranslationY = mHandleViewController.getStashedHandleTranslationY();
 
         mStashedHeight = mHandleViewController.getStashedHeight();
         mUnstashedHeight = mHandleViewController.getUnstashedHeight();
@@ -126,21 +123,17 @@
     }
 
     /**
-     * Animates the bubble bar and handle to their initial state, transitioning from the state where
-     * both views are invisible. Called when the first bubble is added or when the device is
+     * 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.
-     *
-     * <p>The initial state will depend on the current state of the device, i.e. overview, home etc
-     * and whether bubbles are requested to be expanded.
      */
-    public void animateToInitialState(boolean expanding) {
+    private void animateAfterUnlock() {
         AnimatorSet animatorSet = new AnimatorSet();
-        if (expanding || mBubblesShowingOnHome || mBubblesShowingOnOverview) {
+        if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
             mIsStashed = false;
             animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
                     mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
@@ -220,7 +213,7 @@
         if (isSysuiLocked != mIsSysuiLocked) {
             mIsSysuiLocked = isSysuiLocked;
             if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
-                animateToInitialState(false /* expanding */);
+                animateAfterUnlock();
             }
         }
     }
@@ -253,6 +246,11 @@
                 && !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();
@@ -275,7 +273,6 @@
      */
     private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
         AnimatorSet animatorSet = new AnimatorSet();
-        final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f;
 
         AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
         // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
@@ -289,7 +286,8 @@
             firstHalfDurationScale = 0.75f;
             secondHalfDurationScale = 0.5f;
 
-            fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
+            fullLengthAnimatorSet.play(
+                    mIconTranslationYForStash.animateToValue(getStashTranslation()));
 
             firstHalfAnimatorSet.playTogether(
                     mIconAlphaForStash.animateToValue(0),
@@ -338,6 +336,10 @@
         return animatorSet;
     }
 
+    private float getStashTranslation() {
+        return (mUnstashedHeight - mStashedHeight) / 2f;
+    }
+
     private void onIsStashedChanged() {
         mControllers.runAfterInit(() -> {
             mHandleViewController.onIsStashedChanged();
@@ -345,7 +347,7 @@
         });
     }
 
-    private float getBubbleBarTranslationYForTaskbar() {
+    public float getBubbleBarTranslationYForTaskbar() {
         return -mActivity.getDeviceProfile().taskbarBottomMargin;
     }
 
@@ -356,7 +358,7 @@
                 hotseatCellHeight - mUnstashedHeight) / 2;
     }
 
-    float getBubbleBarTranslationY() {
+    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.
@@ -364,6 +366,25 @@
                 : 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);
@@ -374,34 +395,63 @@
         mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
     }
 
-    /** Returns the x position of the center of the stashed handle. */
-    public float getStashedHandleCenterX() {
-        return mHandleViewController.getStashedHandleCenterX();
+    /** Returns the [PhysicsAnimator] for the stashed handle view. */
+    public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
+        return mHandleViewController.getPhysicsAnimator();
     }
 
-    /** Returns the animation for hiding the handle before a new bubble animates in. */
-    public AnimatorSet buildHideHandleAnimationForNewBubble() {
-        AnimatorSet animatorSet = new AnimatorSet();
-        animatorSet.playTogether(
-                mBubbleStashedHandleTranslationY.animateToValue(
-                        NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y),
-                mBubbleStashedHandleAlpha.animateToValue(NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA));
-        animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
-        return animatorSet;
+    /** Notifies taskbar that it should update its touchable region. */
+    public void updateTaskbarTouchRegion() {
+        mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
     }
 
-    /** Sets the alpha value of the stashed handle. */
-    public void setStashAlpha(float alpha) {
-        mBubbleStashedHandleAlpha.setValue(alpha);
+    /** 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();
     }
 
-    /** Returns the animation for showing the handle after a new bubble animated in. */
-    public AnimatorSet buildShowHandleAnimationForNewBubble() {
-        AnimatorSet animatorSet = new AnimatorSet();
-        animatorSet.playTogether(
-                mBubbleStashedHandleTranslationY.animateToValue(0),
-                mBubbleStashedHandleAlpha.animateToValue(1));
-        animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
-        return animatorSet;
+    /** Stashes the bubble bar immediately without animation. */
+    public void stashBubbleBarImmediate() {
+        mHandleViewController.setTranslationYForSwipe(0);
+        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);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 2a5912a..91103d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -29,7 +29,6 @@
 import android.view.ViewOutlineProvider;
 
 import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.taskbar.StashedHandleView;
@@ -40,6 +39,7 @@
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
 
 /**
  * Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -59,12 +59,6 @@
     private int mStashedHandleWidth;
     private int mStashedHandleHeight;
 
-    private final AnimatedFloat mStashedHandleTranslationY =
-            new AnimatedFloat(this::updateTranslationY);
-
-    // Modified when swipe up is happening on the stashed handle or task bar.
-    private float mSwipeUpTranslationY;
-
     // The bounds we want to clip to in the settled state when showing the stashed handle.
     private final Rect mStashedHandleBounds = new Rect();
 
@@ -129,6 +123,11 @@
                 updateBounds(mBarViewController.getBubbleBarLocation()));
     }
 
+    /** Returns the [PhysicsAnimator] for the stashed handle view. */
+    public PhysicsAnimator<View> getPhysicsAnimator() {
+        return PhysicsAnimator.getInstance(mStashedHandleView);
+    }
+
     private void updateBounds(BubbleBarLocation bubbleBarLocation) {
         // As more bubbles get added, the icon bounds become larger. To ensure a consistent
         // handle bar position, we pin it to the edge of the screen.
@@ -238,21 +237,11 @@
         }
     }
 
-    /** Returns an animator for translation Y. */
-    public AnimatedFloat getStashedHandleTranslationY() {
-        return mStashedHandleTranslationY;
-    }
-
     /**
      * Sets the translation of the stashed handle during the swipe up gesture.
      */
     public void setTranslationYForSwipe(float transY) {
-        mSwipeUpTranslationY = transY;
-        updateTranslationY();
-    }
-
-    private void updateTranslationY() {
-        mStashedHandleView.setTranslationY(mStashedHandleTranslationY.value + mSwipeUpTranslationY);
+        mStashedHandleView.setTranslationY(transY);
     }
 
     /**
@@ -262,11 +251,6 @@
         return mStashedHandleAlpha;
     }
 
-    /** Returns the x position of the center of the stashed handle. */
-    public float getStashedHandleCenterX() {
-        return mStashedHandleBounds.exactCenterX();
-    }
-
     /**
      * Creates and returns an Animator that updates the stashed handle  shape and size.
      * When stashed, the shape is a thin rounded pill. When unstashed, the shape morphs into
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index bcdc718..61a6bce 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -22,11 +22,13 @@
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.widget.ImageView;
 
+import androidx.annotation.NonNull;
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.android.launcher3.R;
@@ -47,6 +49,25 @@
     public static final int DEFAULT_PATH_SIZE = 100;
 
     /**
+     * Property to update drag translation value.
+     *
+     * @see BubbleView#getDragTranslationX()
+     * @see BubbleView#setDragTranslationX(float)
+     */
+    public static final FloatProperty<BubbleView> DRAG_TRANSLATION_X = new FloatProperty<>(
+            "dragTranslationX") {
+        @Override
+        public void setValue(@NonNull BubbleView bubbleView, float value) {
+            bubbleView.setDragTranslationX(value);
+        }
+
+        @Override
+        public Float get(BubbleView bubbleView) {
+            return bubbleView.getDragTranslationX();
+        }
+    };
+
+    /**
      * Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
      * another. If any of these flags are set, the dot will not be shown.
      * If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
@@ -66,6 +87,9 @@
     private final ImageView mAppIcon;
     private final int mBubbleSize;
 
+    private float mDragTranslationX;
+    private float mOffsetX;
+
     private DotRenderer mDotRenderer;
     private DotRenderer.DrawParams mDrawParams;
     private int mDotColor;
@@ -126,6 +150,39 @@
         outline.setOval(inset, inset, inset + normalizedSize, inset + normalizedSize);
     }
 
+    /**
+     * Set translation-x while this bubble is being dragged.
+     * Translation applied to the view is a sum of {@code translationX} and offset defined by
+     * {@link #setOffsetX(float)}.
+     */
+    public void setDragTranslationX(float translationX) {
+        mDragTranslationX = translationX;
+        applyDragTranslation();
+    }
+
+    /**
+     * Get translation value applied via {@link #setDragTranslationX(float)}.
+     */
+    public float getDragTranslationX() {
+        return mDragTranslationX;
+    }
+
+    /**
+     * Set offset on x-axis while dragging.
+     * Used to counter parent translation in order to keep the dragged view at the current position
+     * on screen.
+     * Translation applied to the view is a sum of {@code offsetX} and translation defined by
+     * {@link #setDragTranslationX(float)}
+     */
+    public void setOffsetX(float offsetX) {
+        mOffsetX = offsetX;
+        applyDragTranslation();
+    }
+
+    private void applyDragTranslation() {
+        setTranslationX(mDragTranslationX + mOffsetX);
+    }
+
     @Override
     public void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
index edabae2..3f947a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -1,3 +1,5 @@
 atsjenk@google.com
 liranb@google.com
 madym@google.com
+mpodolian@google.com
+
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 1db5103..be935d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -18,16 +18,12 @@
 
 import android.view.View
 import android.view.View.VISIBLE
-import androidx.core.animation.AnimatorSet
-import androidx.core.animation.ObjectAnimator
-import androidx.core.animation.doOnEnd
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.SpringForce
 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.systemui.util.doOnEnd
 import com.android.wm.shell.shared.animation.PhysicsAnimator
 
 /** Handles animations for bubble bar bubbles. */
@@ -39,43 +35,49 @@
     private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
 ) {
 
+    private var animatingBubble: AnimatingBubble? = null
+
     private companion object {
         /** The time to show the flyout. */
         const val FLYOUT_DELAY_MS: Long = 2500
-        /** The translation Y the new bubble will animate to. */
-        const val BUBBLE_ANIMATION_FINAL_TRANSLATION_Y = -50f
-        /** The initial translation Y value the new bubble is set to before the animation starts. */
-        // TODO(liranb): get rid of this and calculate this based on the y-distance between the
-        // bubble and the stash handle.
-        const val BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y = 50f
         /** The initial scale Y value that the new bubble is set to before the animation starts. */
         const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
-        /** The initial alpha value that the new bubble is set to before the animation starts. */
-        const val BUBBLE_ANIMATION_INITIAL_ALPHA = 0.5f
-        /** The duration of the hide bubble animation. */
-        const val HIDE_BUBBLE_ANIMATION_DURATION_MS = 250L
     }
 
+    /** Wrapper around the animating bubble with its show and hide animations. */
+    private data class AnimatingBubble(
+        val bubbleView: BubbleView,
+        val showAnimation: Runnable,
+        val hideAnimation: Runnable
+    )
+
     /** An interface for scheduling jobs. */
     interface Scheduler {
 
         /** Schedule the given [block] to run. */
-        fun post(block: () -> Unit)
+        fun post(block: Runnable)
 
         /** Schedule the given [block] to start with a delay of [delayMillis]. */
-        fun postDelayed(delayMillis: Long, block: () -> Unit)
+        fun postDelayed(delayMillis: Long, block: Runnable)
+
+        /** Cancel the given [block] if it hasn't started yet. */
+        fun cancel(block: Runnable)
     }
 
     /** A [Scheduler] that uses a Handler to run jobs. */
     private class HandlerScheduler(private val view: View) : Scheduler {
 
-        override fun post(block: () -> Unit) {
+        override fun post(block: Runnable) {
             view.post(block)
         }
 
-        override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+        override fun postDelayed(delayMillis: Long, block: Runnable) {
             view.postDelayed(block, delayMillis)
         }
+
+        override fun cancel(block: Runnable) {
+            view.removeCallbacks(block)
+        }
     }
 
     private val springConfig =
@@ -91,95 +93,238 @@
         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 = buildShowAnimation(bubbleView, b.key, animator)
-        val hideAnimation = buildHideAnimation(bubbleView)
+        val showAnimation = buildHandleToBubbleBarAnimation()
+        val hideAnimation = buildBubbleBarToHandleAnimation()
+        animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
         scheduler.post(showAnimation)
         scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
     }
 
     /**
-     * Returns a lambda that starts the animation that shows the new bubble.
+     * Returns a [Runnable] that starts the animation that morphs the handle to the bubble bar.
      *
-     * The animation is divided into 2 parts. First the stash handle starts animating up and fades
-     * out. When it ends the bubble starts fading in. The bubble and stashed handle are aligned to
-     * give the impression of the stash handle morphing into the bubble.
+     * Visually, the animation is divided into 2 parts. The stash handle starts animating up and
+     * fading out and then the bubble bar starts animating up and fading in.
+     *
+     * To make the transition from the handle to the bar smooth, the positions and movement of the 2
+     * views must be synchronized. To do that we use a single spring path along the Y axis, starting
+     * from the handle's position to the eventual bar's position. The path is split into 3 parts.
+     * 1. In the first part, we only animate the handle.
+     * 2. In the second part the handle is fully hidden, and the bubble bar is animating in.
+     * 3. The third part is the overshoot of the spring animation, where we make the bubble fully
+     *    visible which helps avoiding further updates when we re-enter the second part.
      */
-    private fun buildShowAnimation(
-        bubbleView: BubbleView,
-        key: String,
-        bubbleAnimator: PhysicsAnimator<BubbleView>
-    ): () -> Unit = {
-        // calculate the initial translation x the bubble should have in order to align it with the
-        // stash handle.
-        val initialTranslationX =
-            bubbleStashController.stashedHandleCenterX - bubbleView.centerXOnScreen
-        bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
-        bubbleAnimator.setDefaultSpringConfig(springConfig)
-        bubbleAnimator
-            .spring(DynamicAnimation.ALPHA, 1f)
-            .spring(DynamicAnimation.TRANSLATION_Y, BUBBLE_ANIMATION_FINAL_TRANSLATION_Y)
-            .spring(DynamicAnimation.SCALE_Y, 1f)
-        // prepare the bubble for the animation
-        bubbleView.alpha = 0f
-        bubbleView.translationX = initialTranslationX
-        bubbleView.translationY = BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
-        bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
-        bubbleView.visibility = VISIBLE
-        // start the stashed handle animation. when it ends, start the bubble animation.
-        val stashedHandleAnimation = bubbleStashController.buildHideHandleAnimationForNewBubble()
-        stashedHandleAnimation.doOnEnd {
-            bubbleView.alpha = BUBBLE_ANIMATION_INITIAL_ALPHA
-            bubbleAnimator.start()
-            bubbleStashController.setStashAlpha(0f)
+    private fun buildHandleToBubbleBarAnimation() = Runnable {
+        // prepare the bubble bar for the animation
+        bubbleBarView.onAnimatingBubbleStarted()
+        bubbleBarView.visibility = VISIBLE
+        bubbleBarView.alpha = 0f
+        bubbleBarView.translationY = 0f
+        bubbleBarView.scaleX = 1f
+        bubbleBarView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
+        bubbleBarView.relativePivotY = 0.5f
+
+        // this is the offset between the center of the bubble bar and the center of the stash
+        // 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 stashedHandleTranslationY =
+            bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+
+        // 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
+        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 -> {
+                    // 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
+                    handle.alpha = 1 - fraction
+                }
+                ty >= totalTranslationY -> {
+                    // this is the second leg of the animation. the handle should be completely
+                    // hidden and the bubble bar should start animating in.
+                    // it's possible that we're re-entering this leg because this is a spring
+                    // animation, so only set the alpha and scale for the bubble bar if we didn't
+                    // already fully animate in.
+                    handle.alpha = 0f
+                    bubbleBarView.translationY = ty - offset
+                    if (bubbleBarView.alpha != 1f) {
+                        // map the path [stashedHandleTranslationY, totalTranslationY] to [0, 1]
+                        val fraction =
+                            (ty - stashedHandleTranslationY) /
+                                (totalTranslationY - stashedHandleTranslationY)
+                        bubbleBarView.alpha = fraction
+                        bubbleBarView.scaleY =
+                            BUBBLE_ANIMATION_INITIAL_SCALE_Y +
+                                (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+                    }
+                }
+                else -> {
+                    // we're past the target animated value, set the alpha and scale for the bubble
+                    // bar so that it's fully visible and no longer changing, but keep moving it
+                    // along the animation path
+                    bubbleBarView.alpha = 1f
+                    bubbleBarView.scaleY = 1f
+                    bubbleBarView.translationY = ty - offset
+                }
+            }
         }
-        stashedHandleAnimation.start()
+        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
+                return@addEndListener
+            }
+            // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
+            bubbleStashController.updateTaskbarTouchRegion()
+        }
+        animator.start()
     }
 
     /**
-     * Returns a lambda that starts the animation that hides the new bubble.
+     * Returns a [Runnable] that starts the animation that hides the bubble bar and morphs it into
+     * the stashed handle.
      *
-     * Similarly to the show animation, this is divided into 2 parts. We first animate the bubble
-     * out, and then animate the stash handle in. At the end of the animation we reset the values of
-     * the bubble.
+     * Similarly to the show animation, this is visually divided into 2 parts. We first animate the
+     * bubble bar out, and then animate the stash handle in. At the end of the animation we reset
+     * values of the bubble bar.
+     *
+     * This is a spring animation that goes along the same path of the show animation in the
+     * opposite order, and is split into 3 parts:
+     * 1. In the first part the bubble animates out.
+     * 2. In the second part the bubble bar is fully hidden and the handle animates in.
+     * 3. The third part is the overshoot. The handle is made fully visible.
      */
-    private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
-        val stashAnimation = bubbleStashController.buildShowHandleAnimationForNewBubble()
-        val alphaAnimator =
-            ObjectAnimator.ofFloat(bubbleView, View.ALPHA, BUBBLE_ANIMATION_INITIAL_ALPHA)
-        val translationYAnimator =
-            ObjectAnimator.ofFloat(
-                bubbleView,
-                View.TRANSLATION_Y,
-                BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
-            )
-        val scaleYAnimator =
-            ObjectAnimator.ofFloat(bubbleView, View.SCALE_Y, BUBBLE_ANIMATION_INITIAL_SCALE_Y)
-        val hideBubbleAnimation = AnimatorSet()
-        hideBubbleAnimation.playTogether(alphaAnimator, translationYAnimator, scaleYAnimator)
-        hideBubbleAnimation.duration = HIDE_BUBBLE_ANIMATION_DURATION_MS
-        hideBubbleAnimation.doOnEnd {
-            // the bubble is now hidden, start the stash handle animation and reset bubble
-            // properties
-            bubbleStashController.setStashAlpha(
-                BubbleStashController.NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA
-            )
-            bubbleView.alpha = 0f
-            stashAnimation.start()
-            bubbleView.translationY = 0f
-            bubbleView.scaleY = 1f
-            if (bubbleStashController.isStashed) {
-                bubbleBarView.alpha = 0f
+    private fun buildBubbleBarToHandleAnimation() = Runnable {
+        if (animatingBubble == null) return@Runnable
+        val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+        val stashedHandleTranslationY =
+            bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+        // 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
+        animator.setDefaultSpringConfig(springConfig)
+        animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
+        animator.addUpdateListener { handle, values ->
+            val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+            when {
+                ty <= stashedHandleTranslationY -> {
+                    // this is the first leg of the animation. only animate the bubble bar. the
+                    // handle is hidden during this part
+                    bubbleBarView.translationY = ty - offset
+                    // map the path [totalTranslationY, stashedHandleTranslationY] to [0, 1]
+                    val fraction =
+                        (totalTranslationY - ty) / (totalTranslationY - stashedHandleTranslationY)
+                    bubbleBarView.alpha = 1 - fraction
+                    bubbleBarView.scaleY = 1 - (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+                }
+                ty <= 0 -> {
+                    // this is the second part of the animation. make the bubble bar invisible and
+                    // start fading in the handle, but don't update the alpha if it's already fully
+                    // visible
+                    bubbleBarView.alpha = 0f
+                    if (handle.alpha != 1f) {
+                        // map the path [stashedHandleTranslationY, 0] to [0, 1]
+                        val fraction = (stashedHandleTranslationY - ty) / stashedHandleTranslationY
+                        handle.alpha = fraction
+                    }
+                }
+                else -> {
+                    // we reached the target value. set the alpha of the handle to 1
+                    handle.alpha = 1f
+                }
             }
-            bubbleBarView.onAnimatingBubbleCompleted()
         }
-        hideBubbleAnimation.start()
+        animator.addEndListener { _, _, _, canceled, _, _, _ ->
+            animatingBubble = null
+            if (!canceled) bubbleStashController.stashBubbleBarImmediate()
+            bubbleBarView.onAnimatingBubbleCompleted()
+            bubbleBarView.relativePivotY = 1f
+            bubbleStashController.updateTaskbarTouchRegion()
+        }
+        animator.start()
+    }
+
+    /** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
+    fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) {
+        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 if we are in an app.
+        val showAnimation = buildBubbleBarBounceAnimation()
+        val hideAnimation =
+            if (isInApp && !isExpanding) {
+                buildBubbleBarToHandleAnimation()
+            } else {
+                // in this case the bubble bar remains visible so not much to do. once we implement
+                // the flyout we'll update this runnable to hide it.
+                Runnable {
+                    animatingBubble = null
+                    bubbleStashController.showBubbleBarImmediate()
+                    bubbleBarView.onAnimatingBubbleCompleted()
+                }
+            }
+        animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+        scheduler.post(showAnimation)
+        scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
+    }
+
+    private fun buildBubbleBarBounceAnimation() = Runnable {
+        // 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 animator = PhysicsAnimator.getInstance(bubbleBarView)
+        animator.setDefaultSpringConfig(springConfig)
+        animator.spring(DynamicAnimation.TRANSLATION_Y, bubbleStashController.bubbleBarTranslationY)
+        animator.addEndListener { _, _, _, _, _, _, _ ->
+            // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
+            bubbleStashController.updateTaskbarTouchRegion()
+        }
+        animator.start()
+    }
+
+    /** Handles clicking on the animating bubble while the animation is still playing. */
+    fun onBubbleClickedWhileAnimating() {
+        val hideAnimation = animatingBubble?.hideAnimation ?: return
+        scheduler.cancel(hideAnimation)
+        bubbleBarView.onAnimatingBubbleCompleted()
+        bubbleBarView.relativePivotY = 1f
+        animatingBubble = null
+    }
+
+    /** Notifies the animator that the taskbar area was touched during an animation. */
+    fun onStashStateChangingWhileAnimating() {
+        val hideAnimation = animatingBubble?.hideAnimation ?: return
+        scheduler.cancel(hideAnimation)
+        animatingBubble = null
+        bubbleStashController.stashedHandlePhysicsAnimator.cancel()
+        bubbleBarView.onAnimatingBubbleCompleted()
+        bubbleBarView.relativePivotY = 1f
+        bubbleStashController.onNewBubbleAnimationInterrupted(
+            /* isStashed= */ bubbleBarView.alpha == 0f,
+            bubbleBarView.translationY
+        )
     }
 }
-
-/** The X position in screen coordinates of the center of the bubble. */
-private val BubbleView.centerXOnScreen: Float
-    get() {
-        val screenCoordinates = IntArray(2)
-        getLocationOnScreen(screenCoordinates)
-        return screenCoordinates[0] + width / 2f
-    }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index fe91362..e487f9f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -24,10 +24,11 @@
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.Space
+import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
-import com.android.systemui.shared.rotation.RotationButton
 
 /**
  * Meant to be a simple container for data subclasses will need
@@ -41,14 +42,13 @@
  * @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
  */
 abstract class AbstractNavButtonLayoutter(
-        val resources: Resources,
-        val navButtonContainer: LinearLayout,
-        protected val endContextualContainer: ViewGroup,
-        protected val startContextualContainer: ViewGroup,
-        protected val imeSwitcher: ImageView?,
-        protected val rotationButton: RotationButton?,
-        protected val a11yButton: ImageView?,
-        protected val space: Space?
+    val resources: Resources,
+    val navButtonContainer: LinearLayout,
+    protected val endContextualContainer: ViewGroup,
+    protected val startContextualContainer: ViewGroup,
+    protected val imeSwitcher: ImageView?,
+    protected val a11yButton: ImageView?,
+    protected val space: Space?
 ) : NavButtonLayoutter {
     protected val homeButton: ImageView? = navButtonContainer.findViewById(R.id.home)
     protected val recentsButton: ImageView? = navButtonContainer.findViewById(R.id.recent_apps)
@@ -66,17 +66,41 @@
     }
 
     fun getParamsToCenterView(): FrameLayout.LayoutParams {
-        val params = FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+        val params =
+            FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
         params.gravity = Gravity.CENTER
-        return params;
+        return params
     }
 
-    open fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
-                                           barAxisMarginStart: Int, barAxisMarginEnd: Int,
-                                           gravity: Int) {
-        val contextualContainerParams = FrameLayout.LayoutParams(
-                buttonSize, ViewGroup.LayoutParams.MATCH_PARENT)
+    fun adjustForSetupInPhoneMode(
+        navButtonsLayoutParams: FrameLayout.LayoutParams,
+        navButtonsViewLayoutParams: FrameLayout.LayoutParams,
+        deviceProfile: DeviceProfile
+    ) {
+        val phoneOrPortraitSetupMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
+        navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
+        navButtonsLayoutParams.bottomMargin =
+            if (!deviceProfile.isLandscape) 0
+            else
+                phoneOrPortraitSetupMargin -
+                        resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
+        navButtonsViewLayoutParams.height =
+            resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
+    }
+
+    open fun repositionContextualContainer(
+        contextualContainer: ViewGroup,
+        buttonSize: Int,
+        barAxisMarginStart: Int,
+        barAxisMarginEnd: Int,
+        gravity: Int
+    ) {
+        val contextualContainerParams =
+            FrameLayout.LayoutParams(buttonSize, ViewGroup.LayoutParams.MATCH_PARENT)
         contextualContainerParams.apply {
             marginStart = barAxisMarginStart
             marginEnd = barAxisMarginEnd
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index 4368b95..aa8f5a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -29,27 +29,24 @@
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
-import com.android.systemui.shared.rotation.RotationButton
 
 class KidsNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?,
-        space: Space?
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
     AbstractNavButtonLayoutter(
-            resources,
-            navBarContainer,
-            endContextualContainer,
-            startContextualContainer,
-            imeSwitcher,
-            rotationButton,
-            a11yButton,
-            space
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        a11yButton,
+        space
     ) {
 
     override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
@@ -105,11 +102,16 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val contextualMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_contextual_button_padding)
+        val contextualMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_padding)
         repositionContextualContainer(endContextualContainer, WRAP_CONTENT, 0, 0, Gravity.END)
-        repositionContextualContainer(startContextualContainer, WRAP_CONTENT, contextualMargin,
-                contextualMargin, Gravity.START)
+        repositionContextualContainer(
+            startContextualContainer,
+            WRAP_CONTENT,
+            contextualMargin,
+            contextualMargin,
+            Gravity.START
+        )
 
         if (imeSwitcher != null) {
             startContextualContainer.addView(imeSwitcher)
@@ -119,9 +121,5 @@
             endContextualContainer.addView(a11yButton)
             a11yButton.layoutParams = getParamsToCenterView()
         }
-        if (rotationButton != null) {
-            endContextualContainer.addView(rotationButton.currentView)
-            rotationButton.currentView.layoutParams = getParamsToCenterView()
-        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 5bfdce9..2497fbb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -25,10 +25,11 @@
 import android.widget.Space
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
-import com.android.systemui.shared.rotation.RotationButton
 
 /**
  * Select the correct layout for nav buttons
@@ -58,7 +59,6 @@
             deviceProfile: DeviceProfile,
             navButtonsView: NearestTouchFrame,
             imeSwitcher: ImageView?,
-            rotationButton: RotationButton?,
             a11yButton: ImageView?,
             space: Space?,
             resources: Resources,
@@ -86,7 +86,6 @@
                             endContextualContainer,
                             startContextualContainer,
                             imeSwitcher,
-                            rotationButton,
                             a11yButton,
                             space
                         )
@@ -98,7 +97,6 @@
                             endContextualContainer,
                             startContextualContainer,
                             imeSwitcher,
-                            rotationButton,
                             a11yButton,
                             space
                         )
@@ -110,7 +108,6 @@
                             endContextualContainer,
                             startContextualContainer,
                             imeSwitcher,
-                            rotationButton,
                             a11yButton,
                             space
                         )
@@ -119,11 +116,11 @@
                 isPhoneGestureMode -> {
                     PhoneGestureLayoutter(
                         resources,
+                        navButtonsView,
                         navButtonContainer,
                         endContextualContainer,
                         startContextualContainer,
                         imeSwitcher,
-                        rotationButton,
                         a11yButton,
                         space
                     )
@@ -138,7 +135,6 @@
                                 endContextualContainer,
                                 startContextualContainer,
                                 imeSwitcher,
-                                rotationButton,
                                 a11yButton,
                                 space
                             )
@@ -150,7 +146,6 @@
                                 endContextualContainer,
                                 startContextualContainer,
                                 imeSwitcher,
-                                rotationButton,
                                 a11yButton,
                                 space
                             )
@@ -162,7 +157,6 @@
                                 endContextualContainer,
                                 startContextualContainer,
                                 imeSwitcher,
-                                rotationButton,
                                 a11yButton,
                                 space
                             )
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
index bf820c0..390ec34 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
@@ -17,36 +17,60 @@
 package com.android.launcher3.taskbar.navbutton
 
 import android.content.res.Resources
+import android.view.Gravity
 import android.view.ViewGroup
+import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.Space
+import com.android.launcher3.DeviceProfile
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
 
 /** Layoutter for showing gesture navigation on phone screen. No buttons here, no-op container */
 class PhoneGestureLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?,
-        space: Space?
+    resources: Resources,
+    navButtonsView: NearestTouchFrame,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
-        AbstractNavButtonLayoutter(
-                resources,
-                navBarContainer,
-                endContextualContainer,
-                startContextualContainer,
-                imeSwitcher,
-                rotationButton,
-                a11yButton,
-                space
-        ) {
+    AbstractNavButtonLayoutter(
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        a11yButton,
+        space
+    ) {
+    private val mNavButtonsView = navButtonsView
 
     override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
+        // TODO: look into if we should use SetupNavLayoutter instead.
+        if (!context.isUserSetupComplete) {
+            // Since setup wizard only has back button enabled, it looks strange to be
+            // end-aligned, so start-align instead.
+            val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
+            val navButtonsViewLayoutParams =
+                mNavButtonsView.layoutParams as FrameLayout.LayoutParams
+            val deviceProfile: DeviceProfile = context.deviceProfile
+
+            navButtonsLayoutParams.marginEnd = 0
+            navButtonsLayoutParams.gravity = Gravity.START
+            context.setTaskbarWindowSize(context.setupWindowSize)
+
+            adjustForSetupInPhoneMode(
+                navButtonsLayoutParams,
+                navButtonsViewLayoutParams,
+                deviceProfile
+            )
+            mNavButtonsView.layoutParams = navButtonsViewLayoutParams
+            navButtonContainer.layoutParams = navButtonsLayoutParams
+        }
+
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index 6a935f1..9f7f07e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -26,35 +26,32 @@
 import android.widget.Space
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
 
 open class PhoneLandscapeNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?,
-        space: Space?
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
     AbstractNavButtonLayoutter(
-            resources,
-            navBarContainer,
-            endContextualContainer,
-            startContextualContainer,
-            imeSwitcher,
-            rotationButton,
-            a11yButton,
-            space
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        a11yButton,
+        space
     ) {
 
     override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         val totalHeight = context.deviceProfile.heightPx
-        val homeButtonHeight = resources.getDimensionPixelSize(
-                R.dimen.taskbar_phone_home_button_size)
-        val roundedCornerContentMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val homeButtonHeight =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
+        val roundedCornerContentMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
         val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
         val contentWidth = totalHeight - roundedCornerContentMargin * 2 - contentPadding * 2
 
@@ -63,13 +60,13 @@
         val sideButtonHeight = contextualButtonHeight * 2
         val navButtonContainerHeight = contentWidth - contextualButtonHeight * 2
 
-        val navContainerParams = FrameLayout.LayoutParams(
-                MATCH_PARENT, navButtonContainerHeight.toInt())
+        val navContainerParams =
+            FrameLayout.LayoutParams(MATCH_PARENT, navButtonContainerHeight.toInt())
         navContainerParams.apply {
             topMargin =
-                    (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
+                (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
             bottomMargin =
-                    (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
+                (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
             marginEnd = 0
             marginStart = 0
         }
@@ -84,8 +81,8 @@
         navButtonContainer.gravity = Gravity.CENTER
 
         // Add the spaces in between the nav buttons
-        val spaceInBetween = (navButtonContainerHeight - homeButtonHeight -
-                sideButtonHeight * 2) / 2.0f
+        val spaceInBetween =
+            (navButtonContainerHeight - homeButtonHeight - sideButtonHeight * 2) / 2.0f
         for (i in 0 until navButtonContainer.childCount) {
             val navButton = navButtonContainer.getChildAt(i)
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -124,13 +121,23 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val roundedCornerContentMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val roundedCornerContentMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
         val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
-        repositionContextualContainer(startContextualContainer, buttonSize,
-                roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
-        repositionContextualContainer(endContextualContainer, buttonSize,
-                0, roundedCornerContentMargin + contentPadding, Gravity.BOTTOM)
+        repositionContextualContainer(
+            startContextualContainer,
+            buttonSize,
+            roundedCornerContentMargin + contentPadding,
+            0,
+            Gravity.TOP
+        )
+        repositionContextualContainer(
+            endContextualContainer,
+            buttonSize,
+            0,
+            roundedCornerContentMargin + contentPadding,
+            Gravity.BOTTOM
+        )
 
         if (imeSwitcher != null) {
             startContextualContainer.addView(imeSwitcher)
@@ -140,16 +147,16 @@
             startContextualContainer.addView(a11yButton)
             a11yButton.layoutParams = getParamsToCenterView()
         }
-        if (rotationButton != null) {
-            startContextualContainer.addView(rotationButton.currentView)
-            rotationButton.currentView.layoutParams = getParamsToCenterView()
-        }
         endContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
     }
 
-    override fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
-                                               barAxisMarginTop: Int, barAxisMarginBottom: Int,
-                                               gravity: Int) {
+    override fun repositionContextualContainer(
+        contextualContainer: ViewGroup,
+        buttonSize: Int,
+        barAxisMarginTop: Int,
+        barAxisMarginBottom: Int,
+        gravity: Int
+    ) {
         val contextualContainerParams = FrameLayout.LayoutParams(MATCH_PARENT, buttonSize)
         contextualContainerParams.apply {
             marginStart = 0
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index 0672270..5b24ebf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -26,34 +26,32 @@
 import android.widget.Space
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
 
 class PhonePortraitNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?,
-        space: Space?
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
     AbstractNavButtonLayoutter(
-            resources,
-            navBarContainer,
-            endContextualContainer,
-            startContextualContainer,
-            imeSwitcher,
-            rotationButton,
-            a11yButton,
-            space
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        a11yButton,
+        space
     ) {
 
     override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         val totalWidth = context.deviceProfile.widthPx
-        val homeButtonWidth = resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
-        val roundedCornerContentMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val homeButtonWidth =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
+        val roundedCornerContentMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
         val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
         val contentWidth = totalWidth - roundedCornerContentMargin * 2 - contentPadding * 2
 
@@ -62,15 +60,18 @@
         val sideButtonWidth = contextualButtonWidth * 2
         val navButtonContainerWidth = contentWidth - contextualButtonWidth * 2
 
-        val navContainerParams = FrameLayout.LayoutParams(navButtonContainerWidth.toInt(),
-                ViewGroup.LayoutParams.MATCH_PARENT)
+        val navContainerParams =
+            FrameLayout.LayoutParams(
+                navButtonContainerWidth.toInt(),
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
         navContainerParams.apply {
             topMargin = 0
             bottomMargin = 0
             marginEnd =
-                    (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+                (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
             marginStart =
-                    (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+                (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
         }
 
         // Ensure order of buttons is correct
@@ -85,8 +86,8 @@
         navButtonContainer.gravity = Gravity.CENTER
 
         // Add the spaces in between the nav buttons
-        val spaceInBetween = (navButtonContainerWidth - homeButtonWidth -
-                sideButtonWidth * 2) / 2.0f
+        val spaceInBetween =
+            (navButtonContainerWidth - homeButtonWidth - sideButtonWidth * 2) / 2.0f
         for (i in 0 until navButtonContainer.childCount) {
             val navButton = navButtonContainer.getChildAt(i)
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -114,10 +115,20 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        repositionContextualContainer(startContextualContainer, contextualButtonWidth.toInt(),
-                roundedCornerContentMargin + contentPadding, 0, Gravity.START)
-        repositionContextualContainer(endContextualContainer, contextualButtonWidth.toInt(), 0,
-                roundedCornerContentMargin + contentPadding, Gravity.END)
+        repositionContextualContainer(
+            startContextualContainer,
+            contextualButtonWidth.toInt(),
+            roundedCornerContentMargin + contentPadding,
+            0,
+            Gravity.START
+        )
+        repositionContextualContainer(
+            endContextualContainer,
+            contextualButtonWidth.toInt(),
+            0,
+            roundedCornerContentMargin + contentPadding,
+            Gravity.END
+        )
 
         startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
         if (imeSwitcher != null) {
@@ -128,9 +139,5 @@
             endContextualContainer.addView(a11yButton)
             a11yButton.layoutParams = getParamsToCenterView()
         }
-        if (rotationButton != null) {
-            endContextualContainer.addView(rotationButton.currentView)
-            rotationButton.currentView.layoutParams = getParamsToCenterView()
-        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
index 869cc43..f0b47f4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
@@ -1,18 +1,18 @@
 /*
-* 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
-*/
+ * 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.navbutton
 
@@ -24,28 +24,25 @@
 import android.widget.LinearLayout
 import android.widget.Space
 import com.android.launcher3.R
-import com.android.systemui.shared.rotation.RotationButton
 
 class PhoneSeascapeNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?,
-        space: Space?
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
-        PhoneLandscapeNavLayoutter(
-                resources,
-                navBarContainer,
-                endContextualContainer,
-                startContextualContainer,
-                imeSwitcher,
-                rotationButton,
-                a11yButton,
-                space
-        ) {
+    PhoneLandscapeNavLayoutter(
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        a11yButton,
+        space
+    ) {
 
     override fun addThreeButtons() {
         // Flip ordering of back and recents buttons
@@ -58,13 +55,23 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val roundedCornerContentMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val roundedCornerContentMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
         val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
-        repositionContextualContainer(startContextualContainer, buttonSize,
-                roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
-        repositionContextualContainer(endContextualContainer, buttonSize, 0,
-                roundedCornerContentMargin + contentPadding,  Gravity.BOTTOM)
+        repositionContextualContainer(
+            startContextualContainer,
+            buttonSize,
+            roundedCornerContentMargin + contentPadding,
+            0,
+            Gravity.TOP
+        )
+        repositionContextualContainer(
+            endContextualContainer,
+            buttonSize,
+            0,
+            roundedCornerContentMargin + contentPadding,
+            Gravity.BOTTOM
+        )
 
         startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
         if (imeSwitcher != null) {
@@ -75,9 +82,5 @@
             endContextualContainer.addView(a11yButton)
             a11yButton.layoutParams = getParamsToCenterView()
         }
-        if (rotationButton != null) {
-            endContextualContainer.addView(rotationButton.currentView)
-            rotationButton.currentView.layoutParams = getParamsToCenterView()
-        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index 8eff95c..22a3630 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -27,7 +27,6 @@
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
 
 const val SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95
 const val SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05
@@ -39,7 +38,6 @@
     endContextualContainer: ViewGroup,
     startContextualContainer: ViewGroup,
     imeSwitcher: ImageView?,
-    rotationButton: RotationButton?,
     a11yButton: ImageView?,
     space: Space?
 ) :
@@ -49,7 +47,6 @@
         endContextualContainer,
         startContextualContainer,
         imeSwitcher,
-        rotationButton,
         a11yButton,
         space
     ) {
@@ -80,16 +77,11 @@
             navButtonsLayoutParams.height =
                 resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_height)
         } else {
-            val phoneOrPortraitSetupMargin =
-                resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
-            navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
-            navButtonsLayoutParams.bottomMargin =
-                if (!deviceProfile.isLandscape) 0
-                else
-                    phoneOrPortraitSetupMargin -
-                        resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
-            navButtonsViewLayoutParams.height =
-                resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
+            adjustForSetupInPhoneMode(
+                navButtonsLayoutParams,
+                navButtonsViewLayoutParams,
+                deviceProfile
+            )
         }
         mNavButtonsView.layoutParams = navButtonsViewLayoutParams
         navButtonContainer.layoutParams = navButtonsLayoutParams
@@ -116,9 +108,5 @@
             endContextualContainer.addView(a11yButton)
             a11yButton.layoutParams = getParamsToCenterView()
         }
-        if (rotationButton != null) {
-            endContextualContainer.addView(rotationButton.currentView)
-            rotationButton.currentView.layoutParams = getParamsToCenterView()
-        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index 34d3fad..a59e8a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -26,7 +26,6 @@
 import android.widget.Space
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
 
 /** Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode. */
 class TaskbarNavLayoutter(
@@ -35,7 +34,6 @@
     endContextualContainer: ViewGroup,
     startContextualContainer: ViewGroup,
     imeSwitcher: ImageView?,
-    rotationButton: RotationButton?,
     a11yButton: ImageView?,
     space: Space?
 ) :
@@ -45,7 +43,6 @@
         endContextualContainer,
         startContextualContainer,
         imeSwitcher,
-        rotationButton,
         a11yButton,
         space
     ) {
@@ -137,10 +134,6 @@
                 endContextualContainer.addView(a11yButton)
                 a11yButton.layoutParams = getParamsToCenterView()
             }
-            if (rotationButton != null) {
-                endContextualContainer.addView(rotationButton.currentView)
-                rotationButton.currentView.layoutParams = getParamsToCenterView()
-            }
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 6c05bfe..b1bb198 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -64,6 +64,7 @@
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
@@ -87,6 +88,7 @@
 import android.util.AttributeSet;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
 import android.view.View;
 import android.widget.AnalogClock;
 import android.widget.TextClock;
@@ -164,6 +166,8 @@
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
@@ -262,6 +266,10 @@
                         getDepthController(), getStatsLogManager(),
                         systemUiProxy, RecentsModel.INSTANCE.get(this),
                         () -> onStateBack());
+        RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(asContext());
+        // TODO(b/337863494): Explore use of the same OverviewComponentObserver across launcher
+        OverviewComponentObserver overviewComponentObserver = new OverviewComponentObserver(
+                asContext(), deviceState);
         if (enableDesktopWindowingMode()) {
             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
                     getStateManager(), systemUiProxy, getIApplicationThread(),
@@ -270,7 +278,7 @@
         overviewPanel.init(mActionsView, mSplitSelectStateController,
                 mDesktopRecentsTransitionController);
         mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
-                mSplitSelectStateController);
+                mSplitSelectStateController, overviewComponentObserver, deviceState);
         mSplitToWorkspaceController = new SplitToWorkspaceController(this,
                 mSplitSelectStateController);
         mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
@@ -285,7 +293,8 @@
         if (enableDesktopWindowingMode()) {
             mDesktopVisibilityController = new DesktopVisibilityController(this);
             mDesktopVisibilityController.registerSystemUiListener();
-            mSplitSelectStateController.initSplitFromDesktopController(this);
+            mSplitSelectStateController.initSplitFromDesktopController(this,
+                    overviewComponentObserver);
         }
         mHotseatPredictionController = new HotseatPredictionController(this);
 
@@ -389,6 +398,12 @@
     }
 
     @Override
+    public void startBinding() {
+        super.startBinding();
+        mHotseatPredictionController.verifyUIUpdateNotPaused();
+    }
+
+    @Override
     protected void onActivityFlagsChanged(int changeBits) {
         if ((changeBits & ACTIVITY_STATE_STARTED) != 0) {
             mDepthController.setActivityStarted(isStarted());
@@ -840,6 +855,28 @@
     }
 
     @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return tryHandleBackKey(event) || super.dispatchKeyEvent(event);
+    }
+
+    // TODO (b/267248420) Once the recents input consumer has been removed, there is no need to
+    //  handle the back key specially.
+    private boolean tryHandleBackKey(KeyEvent event) {
+        // Unlike normal activity, recents can receive input event from InputConsumer, so the input
+        // event won't go through ViewRootImpl#InputStage#onProcess.
+        // So when receive back key, try to do the same check thing in
+        // ViewRootImpl#NativePreImeInputStage#onProcess
+        if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
+                || event.getKeyCode() != KeyEvent.KEYCODE_BACK
+                || event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
+            return false;
+        }
+
+        getOnBackAnimationCallback().onBackInvoked();
+        return true;
+    }
+
+    @Override
     protected void registerBackDispatcher() {
         if (!enablePredictiveBackGesture()) {
             super.registerBackDispatcher();
@@ -942,12 +979,12 @@
 
     @Override
     public void setResumed() {
-        if (mDesktopVisibilityController != null
+        if (!enableDesktopWindowingWallpaperActivity()
+                && mDesktopVisibilityController != null
                 && mDesktopVisibilityController.areDesktopTasksVisible()
                 && !mDesktopVisibilityController.isRecentsGestureInProgress()) {
             // Return early to skip setting activity to appear as resumed
-            // TODO(b/255649902): shouldn't be needed when we have a separate launcher state
-            //  for desktop that we can use to control other parts of launcher
+            // TODO: b/333533253 - Remove after flag rollout
             return;
         }
         super.setResumed();
@@ -1186,6 +1223,7 @@
         switch (info.container) {
             case Favorites.CONTAINER_DESKTOP:
             case Favorites.CONTAINER_HOTSEAT:
+            case Favorites.CONTAINER_PRIVATESPACE:
                 // Fall through and continue it's on the workspace (we don't support swiping back
                 // to other containers like all apps or the hotseat predictions (which can change)
                 break;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 6c1d4b1..317e6f2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
-import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -50,6 +49,7 @@
 import com.android.quickstep.util.SplitAnimationTimings;
 import com.android.quickstep.views.ClearAllButton;
 import com.android.quickstep.views.LauncherRecentsView;
+import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 
 /**
@@ -167,8 +167,8 @@
         propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
                 clearAllButtonAlpha, LINEAR);
         float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
-        propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
-                MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator(
+        propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlphaSetter(),
+                OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, config.getInterpolator(
                         ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
index e94fa61..3881e9a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -16,32 +16,98 @@
 
 package com.android.launcher3.uioverrides.flags
 
+import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.net.Uri
-import android.os.Handler
 import android.provider.DeviceConfig
 import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
 import android.text.Html
+import android.util.AttributeSet
 import android.view.inputmethod.EditorInfo
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.widget.doAfterTextChanged
 import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
 import androidx.preference.PreferenceGroup
 import androidx.preference.PreferenceViewHolder
 import androidx.preference.SwitchPreference
 import com.android.launcher3.ExtendedEditText
+import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.R
+import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
+import com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN
+import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
 import com.android.launcher3.util.PluginManagerWrapper
 import com.android.quickstep.util.DeviceConfigHelper
 import com.android.quickstep.util.DeviceConfigHelper.Companion.NAMESPACE_LAUNCHER
 import com.android.quickstep.util.DeviceConfigHelper.DebugInfo
 import com.android.systemui.shared.plugins.PluginEnabler
+import com.android.systemui.shared.plugins.PluginPrefs
+import java.util.Locale
 
 /** Helper class to generate UI for Device Config */
-class DevOptionsUiHelper {
+class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, attr) {
+
+    init {
+        layoutResource = R.layout.developer_options_top_bar
+        isPersistent = false
+    }
+
+    override fun onBindViewHolder(holder: PreferenceViewHolder) {
+        super.onBindViewHolder(holder)
+
+        // Initialize search
+        (holder.findViewById(R.id.filter_box) as TextView?)?.doAfterTextChanged {
+            val query: String = it.toString().lowercase(Locale.getDefault()).replace("_", " ")
+            filterPreferences(query, this)
+        }
+    }
+
+    private fun filterPreferences(query: String, pg: PreferenceGroup) {
+        val count = pg.preferenceCount
+        var visible = false
+        for (i in 0 until count) {
+            val preference = pg.getPreference(i)
+            if (preference is PreferenceGroup) {
+                filterPreferences(query, preference)
+            } else {
+                val title =
+                    preference.title.toString().lowercase(Locale.getDefault()).replace("_", " ")
+                preference.isVisible = query.isEmpty() || title.contains(query)
+            }
+            visible = visible or preference.isVisible
+        }
+        pg.isVisible = visible
+    }
+
+    override fun onAttached() {
+        super.onAttached()
+
+        removeAll()
+        inflateServerFlags(newCategory("Server flags", "Long press to reset"))
+        if (PluginPrefs.hasPlugins(context)) {
+            inflatePluginPrefs(newCategory("Plugins"))
+        }
+        addIntentTargets()
+        addOnboardingPrefsCategory()
+    }
+
+    private fun newCategory(titleText: String, subTitleText: String? = null) =
+        PreferenceCategory(context).apply {
+            title = titleText
+            summary = subTitleText
+            this@DevOptionsUiHelper.addPreference(this)
+        }
 
     /** Inflates preferences for all server flags in the provider PreferenceGroup */
-    fun inflateServerFlags(parent: PreferenceGroup) {
+    private fun inflateServerFlags(parent: PreferenceGroup) {
         val prefs = DeviceConfigHelper.prefs
         // Sort the keys in the order of modified first followed by natural order
         val allProps =
@@ -59,25 +125,21 @@
             if (it.isInt) return@forEach
             val info = it as DebugInfo<Boolean>
 
-            val preference =
-                object : SwitchPreference(parent.context) {
-                    override fun onBindViewHolder(holder: PreferenceViewHolder) {
-                        super.onBindViewHolder(holder)
-                        holder.itemView.setOnLongClickListener {
-                            prefs.edit().remove(key).apply()
-                            setChecked(info.getBoolValue())
-                            summary = info.getSummary()
-                            true
-                        }
-                    }
+            val preference = CustomSwitchPref { holder, pref ->
+                holder.itemView.setOnLongClickListener {
+                    prefs.edit().remove(pref.key).apply()
+                    pref.setChecked(info.getBoolValue())
+                    summary = info.getSummary()
+                    true
                 }
+            }
             preference.key = info.key
             preference.isPersistent = false
             preference.title = info.key
             preference.summary = info.getSummary()
             preference.setChecked(prefs.getBoolean(info.key, info.getBoolValue()))
             preference.setOnPreferenceChangeListener { _, newVal ->
-                DeviceConfigHelper.prefs.edit().putBoolean(info.key, newVal as Boolean).apply()
+                prefs.edit().putBoolean(info.key, newVal as Boolean).apply()
                 preference.summary = info.getSummary()
                 true
             }
@@ -89,36 +151,29 @@
             if (!it.isInt) return@forEach
             val info = it as DebugInfo<Int>
 
-            val preference =
-                object : Preference(parent.context) {
-                    override fun onBindViewHolder(holder: PreferenceViewHolder) {
-                        super.onBindViewHolder(holder)
-                        val textView = holder.findViewById(R.id.pref_edit_text) as ExtendedEditText
-                        textView.setText(info.getIntValueAsString())
-                        textView.setOnEditorActionListener { _, actionId, _ ->
-                            if (actionId == EditorInfo.IME_ACTION_DONE) {
-                                DeviceConfigHelper.prefs
-                                    .edit()
-                                    .putInt(key, textView.text.toString().toInt())
-                                    .apply()
-                                Handler().post { summary = info.getSummary() }
-                                true
-                            }
-                            false
-                        }
-                        textView.setOnBackKeyListener {
-                            textView.setText(info.getIntValueAsString())
-                            true
-                        }
-
-                        holder.itemView.setOnLongClickListener {
-                            prefs.edit().remove(key).apply()
-                            textView.setText(info.getIntValueAsString())
-                            summary = info.getSummary()
-                            true
-                        }
+            val preference = CustomPref { holder, pref ->
+                val textView = holder.findViewById(R.id.pref_edit_text) as ExtendedEditText
+                textView.setText(info.getIntValueAsString())
+                textView.setOnEditorActionListener { _, actionId, _ ->
+                    if (actionId == EditorInfo.IME_ACTION_DONE) {
+                        prefs.edit().putInt(pref.key, textView.text.toString().toInt()).apply()
+                        pref.summary = info.getSummary()
+                        true
                     }
+                    false
                 }
+                textView.setOnBackKeyListener {
+                    textView.setText(info.getIntValueAsString())
+                    true
+                }
+
+                holder.itemView.setOnLongClickListener {
+                    prefs.edit().remove(pref.key).apply()
+                    textView.setText(info.getIntValueAsString())
+                    pref.summary = info.getSummary()
+                    true
+                }
+            }
             preference.key = info.key
             preference.isPersistent = false
             preference.title = info.key
@@ -158,8 +213,7 @@
      * corresponding plugins on the device. When a plugin-group is enabled/disabled we also need to
      * notify the pluginManager manually since the broadcast-mechanism only works in sysui process
      */
-    fun inflatePluginPrefs(parent: PreferenceGroup) {
-        val context = parent.context
+    private fun inflatePluginPrefs(parent: PreferenceGroup) {
         val manager = PluginManagerWrapper.INSTANCE[context] as PluginManagerWrapperImpl
         val pm = context.packageManager
 
@@ -185,15 +239,12 @@
                 val pluginInfo = infoList[0]!!
                 val pluginUri = Uri.fromParts("package", pluginInfo.serviceInfo.packageName, null)
 
-                object : SwitchPreference(context) {
-                        override fun onBindViewHolder(holder: PreferenceViewHolder) {
-                            super.onBindViewHolder(holder)
-                            holder.itemView.setOnLongClickListener {
-                                context.startActivity(
-                                    Intent(ACTION_APPLICATION_DETAILS_SETTINGS, pluginUri)
-                                )
-                                true
-                            }
+                CustomSwitchPref { holder, _ ->
+                        holder.itemView.setOnLongClickListener {
+                            context.startActivity(
+                                Intent(ACTION_APPLICATION_DETAILS_SETTINGS, pluginUri)
+                            )
+                            true
                         }
                     }
                     .apply {
@@ -232,6 +283,113 @@
             }
     }
 
+    private fun addIntentTargets() {
+        val launchSandboxIntent =
+            Intent("com.android.quickstep.action.GESTURE_SANDBOX")
+                .setPackage(context.packageName)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        newCategory("Gesture Navigation Sandbox").apply {
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Gesture Tutorial Steps menu"
+                    intent = Intent(launchSandboxIntent).putExtra("use_tutorial_menu", true)
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Back Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("BACK_NAVIGATION"))
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Home Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("HOME_NAVIGATION"))
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Overview Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("OVERVIEW_NAVIGATION"))
+                }
+            )
+        }
+
+        newCategory("Other activity targets").apply {
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Secondary Display"
+                    intent =
+                        Intent(context, SecondaryDisplayLauncher::class.java)
+                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                }
+            )
+        }
+    }
+
+    private fun addOnboardingPrefsCategory() {
+        newCategory("Onboarding Flows").apply {
+            summary = "Reset these if you want to see the education again."
+            addOnboardPref(
+                "All Apps Bounce",
+                HOME_BOUNCE_SEEN.sharedPrefKey,
+                HOME_BOUNCE_COUNT.sharedPrefKey
+            )
+            addOnboardPref(
+                "Hybrid Hotseat Education",
+                HOTSEAT_DISCOVERY_TIP_COUNT.sharedPrefKey,
+                HOTSEAT_LONGPRESS_TIP_SEEN.sharedPrefKey
+            )
+            addOnboardPref("Taskbar Education", TASKBAR_EDU_TOOLTIP_STEP.sharedPrefKey)
+            addOnboardPref("All Apps Visited Count", ALL_APPS_VISITED_COUNT.sharedPrefKey)
+        }
+    }
+
+    private fun PreferenceCategory.addOnboardPref(title: String, vararg keys: String) =
+        this.addPreference(
+            Preference(context).also {
+                it.title = title
+                it.summary = "Tap to reset"
+                setOnPreferenceClickListener { _ ->
+                    LauncherPrefs.getPrefs(context)
+                        .edit()
+                        .apply { keys.forEach { key -> remove(key) } }
+                        .apply()
+                    Toast.makeText(context, "Reset $title", Toast.LENGTH_SHORT).show()
+                    true
+                }
+            }
+        )
+
+    private inner class CustomSwitchPref(
+        private val bindCallback: (holder: PreferenceViewHolder, pref: SwitchPreference) -> Unit
+    ) : SwitchPreference(context) {
+
+        override fun onBindViewHolder(holder: PreferenceViewHolder) {
+            super.onBindViewHolder(holder)
+            bindCallback.invoke(holder, this)
+        }
+    }
+
+    private inner class CustomPref(
+        private val bindCallback: (holder: PreferenceViewHolder, pref: Preference) -> Unit
+    ) : Preference(context) {
+
+        override fun onBindViewHolder(holder: PreferenceViewHolder) {
+            super.onBindViewHolder(holder)
+            bindCallback.invoke(holder, this)
+        }
+    }
+
     companion object {
         const val TAG = "DeviceConfigUIHelper"
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
deleted file mode 100644
index ca8da08..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.flags;
-
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_HIGHLIGHT_KEY;
-import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
-import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN;
-import static com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceScreen;
-
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
-import com.android.systemui.shared.plugins.PluginPrefs;
-
-/**
- * Dev-build only UI allowing developers to toggle flag settings and plugins.
- * See {@link FeatureFlags}.
- */
-public class DeveloperOptionsUI {
-
-    private final PreferenceFragmentCompat mFragment;
-    private final PreferenceScreen mPreferenceScreen;
-
-    public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) {
-        mFragment = fragment;
-        mPreferenceScreen = fragment.getPreferenceScreen();
-        flags.getParent().removePreference(flags);
-
-        // Add search bar
-        View listView = mFragment.getListView();
-        ViewGroup parent = (ViewGroup) listView.getParent();
-        View topBar = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.developer_options_top_bar, parent, false);
-        parent.addView(topBar, parent.indexOfChild(listView));
-        initSearch(topBar.findViewById(R.id.filter_box));
-
-        DevOptionsUiHelper uiHelper = new DevOptionsUiHelper();
-        uiHelper.inflateServerFlags(newCategory("Server flags"));
-        if (PluginPrefs.hasPlugins(getContext())) {
-            uiHelper.inflatePluginPrefs(newCategory("Plugins"));
-        }
-
-        maybeAddSandboxCategory();
-        addOnboardingPrefsCatergory();
-    }
-
-    private void filterPreferences(String query, PreferenceGroup pg) {
-        int count = pg.getPreferenceCount();
-        int hidden = 0;
-        for (int i = 0; i < count; i++) {
-            Preference preference = pg.getPreference(i);
-            if (preference instanceof PreferenceGroup) {
-                filterPreferences(query, (PreferenceGroup) preference);
-            } else {
-                String title = preference.getTitle().toString().toLowerCase().replace("_", " ");
-                if (query.isEmpty() || title.contains(query)) {
-                    preference.setVisible(true);
-                } else {
-                    preference.setVisible(false);
-                    hidden++;
-                }
-            }
-        }
-        pg.setVisible(hidden != count);
-    }
-
-    private void initSearch(EditText filterBox) {
-        filterBox.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { }
-
-            @Override
-            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { }
-
-            @Override
-            public void afterTextChanged(Editable editable) {
-                String query = editable.toString().toLowerCase().replace("_", " ");
-                filterPreferences(query, mPreferenceScreen);
-            }
-        });
-
-        if (mFragment.getArguments() != null) {
-            String filter = mFragment.getArguments().getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY);
-            // Normally EXTRA_FRAGMENT_ARG_KEY is used to highlight the preference with the given
-            // key. This is a slight variation where we instead filter by the human-readable titles.
-            if (filter != null) {
-                filterBox.setText(filter);
-            }
-        }
-    }
-
-    private PreferenceCategory newCategory(String title) {
-        PreferenceCategory category = new PreferenceCategory(getContext());
-        category.setOrder(Preference.DEFAULT_ORDER);
-        category.setTitle(title);
-        mPreferenceScreen.addPreference(category);
-        return category;
-    }
-
-    private Context getContext() {
-        return mFragment.requireContext();
-    }
-
-    private void maybeAddSandboxCategory() {
-        Context context = getContext();
-        if (context == null) {
-            return;
-        }
-        Intent launchSandboxIntent =
-                new Intent("com.android.quickstep.action.GESTURE_SANDBOX")
-                        .setPackage(context.getPackageName())
-                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (launchSandboxIntent.resolveActivity(context.getPackageManager()) == null) {
-            return;
-        }
-        PreferenceCategory sandboxCategory = newCategory("Gesture Navigation Sandbox");
-        sandboxCategory.setSummary("Learn and practice navigation gestures");
-        Preference launchTutorialStepMenuPreference = new Preference(context);
-        launchTutorialStepMenuPreference.setKey("launchTutorialStepMenu");
-        launchTutorialStepMenuPreference.setTitle("Launch Gesture Tutorial Steps menu");
-        launchTutorialStepMenuPreference.setSummary("Select a gesture tutorial step.");
-        launchTutorialStepMenuPreference.setIntent(
-                new Intent(launchSandboxIntent).putExtra("use_tutorial_menu", true));
-
-        sandboxCategory.addPreference(launchTutorialStepMenuPreference);
-        Preference launchOnboardingTutorialPreference = new Preference(context);
-        launchOnboardingTutorialPreference.setKey("launchOnboardingTutorial");
-        launchOnboardingTutorialPreference.setTitle("Launch Onboarding Tutorial");
-        launchOnboardingTutorialPreference.setSummary("Learn the basic navigation gestures.");
-        launchTutorialStepMenuPreference.setIntent(new Intent(launchSandboxIntent)
-                .putExtra("use_tutorial_menu", false)
-                .putExtra("tutorial_steps",
-                        new String[] {
-                                "HOME_NAVIGATION",
-                                "BACK_NAVIGATION",
-                                "OVERVIEW_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchOnboardingTutorialPreference);
-        Preference launchBackTutorialPreference = new Preference(context);
-        launchBackTutorialPreference.setKey("launchBackTutorial");
-        launchBackTutorialPreference.setTitle("Launch Back Tutorial");
-        launchBackTutorialPreference.setSummary("Learn how to use the Back gesture");
-        launchBackTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"BACK_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchBackTutorialPreference);
-        Preference launchHomeTutorialPreference = new Preference(context);
-        launchHomeTutorialPreference.setKey("launchHomeTutorial");
-        launchHomeTutorialPreference.setTitle("Launch Home Tutorial");
-        launchHomeTutorialPreference.setSummary("Learn how to use the Home gesture");
-        launchHomeTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"HOME_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchHomeTutorialPreference);
-        Preference launchOverviewTutorialPreference = new Preference(context);
-        launchOverviewTutorialPreference.setKey("launchOverviewTutorial");
-        launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial");
-        launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture");
-        launchOverviewTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"OVERVIEW_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchOverviewTutorialPreference);
-        Preference launchSecondaryDisplayPreference = new Preference(context);
-        launchSecondaryDisplayPreference.setKey("launchSecondaryDisplay");
-        launchSecondaryDisplayPreference.setTitle("Launch Secondary Display");
-        launchSecondaryDisplayPreference.setSummary("Launch secondary display activity");
-        launchSecondaryDisplayPreference.setIntent(
-                new Intent(context, SecondaryDisplayLauncher.class));
-
-    }
-
-    private void addOnboardingPrefsCatergory() {
-        PreferenceCategory onboardingCategory = newCategory("Onboarding Flows");
-        onboardingCategory.setSummary("Reset these if you want to see the education again.");
-
-        onboardingCategory.addPreference(createOnboardPref("All Apps Bounce",
-                HOME_BOUNCE_SEEN.getSharedPrefKey(), HOME_BOUNCE_COUNT.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("Hybrid Hotseat Education",
-                HOTSEAT_DISCOVERY_TIP_COUNT.getSharedPrefKey(),
-                HOTSEAT_LONGPRESS_TIP_SEEN.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("Taskbar Education",
-                TASKBAR_EDU_TOOLTIP_STEP.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("All Apps Visited Count",
-                ALL_APPS_VISITED_COUNT.getSharedPrefKey()));
-    }
-
-    private Preference createOnboardPref(String title, String... keys) {
-        Preference onboardingPref = new Preference(getContext());
-        onboardingPref.setTitle(title);
-        onboardingPref.setSummary("Tap to reset");
-        onboardingPref.setOnPreferenceClickListener(preference -> {
-            SharedPreferences.Editor sharedPrefsEdit = LauncherPrefs.getPrefs(getContext())
-                    .edit();
-            for (String key : keys) {
-                sharedPrefsEdit.remove(key);
-            }
-            sharedPrefsEdit.apply();
-            Toast.makeText(getContext(), "Reset " + title, Toast.LENGTH_SHORT).show();
-            return true;
-        });
-        return onboardingPref;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 615e3e3..3ed2d0b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -19,7 +19,7 @@
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
-import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
+import static com.android.launcher3.LauncherAnimUtils.newSingleUseCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
@@ -47,7 +47,6 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.TaskUtils;
@@ -166,7 +165,7 @@
             topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder);
         }
         mCurrentAnimation = builder.createPlaybackController();
-        mCurrentAnimation.getTarget().addListener(newCancelListener(this::clearState));
+        mCurrentAnimation.getTarget().addListener(newSingleUseCancelListener(this::clearState));
     }
 
     private void clearState() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 26e994f..42be52f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -18,7 +18,7 @@
 
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
-import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
+import static com.android.launcher3.LauncherAnimUtils.newSingleUseCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -226,7 +226,7 @@
             return;
         }
         mNormalToHintOverviewScrimAnimator = null;
-        mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
+        mCurrentAnimation.getTarget().addListener(newSingleUseCancelListener(() ->
                 mLauncher.getStateManager().goToState(OVERVIEW, true, forSuccessCallback(() -> {
                     mOverviewResistYAnim = AnimatorControllerWithResistance
                             .createRecentsResistanceFromOverviewAnim(mLauncher, null)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 5a19ed4..fc0df76 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -109,7 +109,7 @@
     private final float mMotionPauseMinDisplacement;
     private final RecentsView mRecentsView;
     protected final AnimatorListener mClearStateOnCancelListener =
-            newCancelListener(this::clearState);
+            newCancelListener(this::clearState, /* isSingleUse = */ false);
 
     private boolean mNoIntercept;
     private LauncherState mStartState;
@@ -248,7 +248,7 @@
         TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, fromState.showTaskThumbnailSplash() ? 1f : 0);
         mRecentsView.setContentAlpha(1);
         mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
-        mLauncher.getActionsView().getVisibilityAlpha().setValue(
+        mLauncher.getActionsView().getVisibilityAlphaSetter().accept(
                 (fromState.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0 ? 1f : 0f);
         mRecentsView.setTaskIconScaledDown(true);
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 05a55d0..16185f5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -151,7 +151,7 @@
             int sysuiFlags = 0;
             TaskView tv = mOverviewPanel.getTaskViewAt(0);
             if (tv != null) {
-                sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+                sysuiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
             }
             mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags);
         } else {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 300d697..26b528c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -252,7 +252,7 @@
                     mTaskBeingDragged, maxDuration, currentInterpolator);
 
             // Since the thumbnail is what is filling the screen, based the end displacement on it.
-            View thumbnailView = mTaskBeingDragged.getThumbnail();
+            View thumbnailView = mTaskBeingDragged.getFirstThumbnailView();
             mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
             dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
             mEndDisplacement = secondaryLayerDimension - mTempCords[1];
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2fedb6f..28ae3d2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.BaseActivity.EVENT_STARTED;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.PagedView.INVALID_PAGE;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -38,8 +39,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 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.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -136,10 +135,11 @@
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -148,12 +148,14 @@
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.OptionalInt;
@@ -922,7 +924,7 @@
             TaskView runningTask = mRecentsView.getRunningTaskView();
             TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
             int centermostTaskFlags = centermostTask == null ? 0
-                    : centermostTask.getThumbnail().getSysUiStatusNavFlags();
+                    : centermostTask.getFirstThumbnailView().getSysUiStatusNavFlags();
             boolean swipeUpThresholdPassed = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
             boolean quickswitchThresholdPassed = centermostTask != runningTask;
 
@@ -1254,15 +1256,20 @@
             return LAST_TASK;
         }
 
-        if (((mRecentsView.getNextPageTaskView() != null
-                && mRecentsView.getNextPageTaskView().isDesktopTask())
-                || (mRecentsView.getCurrentPageTaskView() != null
-                && mRecentsView.getCurrentPageTaskView().isDesktopTask()))
-                && endTarget == NEW_TASK) {
-            // TODO(b/268075592): add support for quickswitch to/from desktop
-            return LAST_TASK;
-        }
+        TaskView nextPageTaskView = mRecentsView != null
+                ? mRecentsView.getNextPageTaskView() : null;
+        TaskView currentPageTaskView = mRecentsView != null
+                ? mRecentsView.getCurrentPageTaskView() : null;
 
+        if (Flags.enableDesktopWindowingMode()
+                && !(Flags.enableDesktopWindowingWallpaperActivity()
+                && Flags.enableDesktopWindowingQuickSwitch())) {
+            if ((nextPageTaskView instanceof DesktopTaskView
+                    || currentPageTaskView instanceof DesktopTaskView)
+                    && endTarget == NEW_TASK) {
+                return LAST_TASK;
+            }
+        }
         return endTarget;
     }
 
@@ -1419,14 +1426,27 @@
             mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
             setClampScrollOffset(false);
         };
-        if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
-                && !mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
-            ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
-                    .SET_ON_PAGE_TRANSITION_END_CALLBACK);
-            // TODO(b/268075592): add support for quickswitch to/from desktop
-            mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+
+        if (Flags.enableDesktopWindowingMode()
+                && !(Flags.enableDesktopWindowingWallpaperActivity()
+                && Flags.enableDesktopWindowingQuickSwitch())) {
+            if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
+                    && !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
+                ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
+                        .SET_ON_PAGE_TRANSITION_END_CALLBACK);
+                mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+            } else {
+                onPageTransitionEnd.run();
+            }
         } else {
-            onPageTransitionEnd.run();
+            if (mRecentsView != null) {
+                ActiveGestureLog.INSTANCE.trackEvent(
+                        ActiveGestureErrorDetector
+                                .GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK);
+                mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+            } else {
+                onPageTransitionEnd.run();
+            }
         }
 
         animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
@@ -1480,8 +1500,12 @@
     }
 
     protected abstract HomeAnimationFactory createHomeAnimationFactory(
-            ArrayList<IBinder> launchCookies, long duration, boolean isTargetTranslucent,
-            boolean appCanEnterPip, RemoteAnimationTarget runningTaskTarget);
+            List<IBinder> launchCookies,
+            long duration,
+            boolean isTargetTranslucent,
+            boolean appCanEnterPip,
+            RemoteAnimationTarget runningTaskTarget,
+            @Nullable TaskView targetTaskView);
 
     private final TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
         @Override
@@ -1555,9 +1579,16 @@
                     && runningTaskTarget.allowEnterPip
                     && runningTaskTarget.taskInfo.pictureInPictureParams != null
                     && runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
-            HomeAnimationFactory homeAnimFactory =
-                    createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
-                            runningTaskTarget);
+            HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(
+                    cookies,
+                    duration,
+                    isTranslucent,
+                    appCanEnterPip,
+                    runningTaskTarget,
+                    !enableAdditionalHomeAnimations()
+                            || mRecentsView == null
+                            || mRecentsView.getCurrentPage() == mRecentsView.getRunningTaskIndex()
+                                    ? null : mRecentsView.getCurrentPageTaskView());
             SwipePipToHomeAnimator swipePipToHomeAnimator = !mIsSwipeForSplit && appCanEnterPip
                     ? createWindowAnimationToPip(homeAnimFactory, runningTaskTarget, start)
                     : null;
@@ -1649,12 +1680,6 @@
                         int taskToLaunch = mRecentsView.getNextPage();
                         int runningTask = getLastAppearedTaskIndex();
                         boolean hasStartedNewTask = hasStartedNewTask();
-                        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                                "taskToLaunch=" + taskToLaunch);
-                        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                                "runningTask=" + runningTask);
-                        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                                "hasStartedNewTask=" + hasStartedNewTask);
                         if (target == NEW_TASK && taskToLaunch == runningTask
                                 && !hasStartedNewTask) {
                             // We are about to launch the current running task, so use LAST_TASK
@@ -2243,13 +2268,14 @@
                     mRecentsAnimationController, mRecentsAnimationTargets);
         });
 
-        if ((mRecentsView.getNextPageTaskView() != null
-                && mRecentsView.getNextPageTaskView().isDesktopTask())
-                || (mRecentsView.getCurrentPageTaskView() != null
-                && mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
-            // TODO(b/268075592): add support for quickswitch to/from desktop
-            mRecentsViewScrollLinked = false;
-            return;
+        if (Flags.enableDesktopWindowingMode()
+                && !(Flags.enableDesktopWindowingWallpaperActivity()
+                        && Flags.enableDesktopWindowingQuickSwitch())) {
+            if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
+                    || mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
+                mRecentsViewScrollLinked = false;
+                return;
+            }
         }
 
         // Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
@@ -2280,15 +2306,15 @@
                 int[] taskIds = nextTask.getTaskIds();
                 ActiveGestureLog.CompoundString nextTaskLog = new ActiveGestureLog.CompoundString(
                         "Launching task: ");
-                for (TaskIdAttributeContainer c : nextTask.getTaskIdAttributeContainers()) {
-                    if (c == null) {
+                for (TaskContainer container : nextTask.getTaskContainers()) {
+                    if (container == null) {
                         continue;
                     }
                     nextTaskLog
                             .append("[id: ")
-                            .append(c.getTask().key.id)
+                            .append(container.getTask().key.id)
                             .append(", pkg: ")
-                            .append(c.getTask().key.getPackageName())
+                            .append(container.getTask().key.getPackageName())
                             .append("] | ");
                 }
                 mGestureState.updateLastStartedTaskIds(taskIds);
@@ -2400,7 +2426,7 @@
         RemoteAnimationTarget taskTarget = taskTargetOptional.get();
         TaskView taskView = mRecentsView == null
                 ? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId);
-        if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) {
+        if (taskView == null || !taskView.getFirstThumbnailView().shouldShowSplashView()) {
             ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state");
             finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
             return;
diff --git a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
deleted file mode 100644
index 2fc4d04..0000000
--- a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
+++ /dev/null
@@ -1,52 +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.quickstep
-
-import android.content.Context
-import android.util.Log
-import com.android.launcher3.LauncherAppState
-import com.android.launcher3.LauncherPrefs
-import com.android.launcher3.moveStartupDataToDeviceProtectedStorageIsEnabled
-import com.android.launcher3.util.LockedUserState
-
-/**
- * Loads expensive objects in memory before the user is unlocked. This decreases experienced latency
- * when starting the launcher for the first time after a reboot.
- */
-object BootAwarePreloader {
-    private const val TAG = "BootAwarePreloader"
-
-    @JvmStatic
-    fun start(context: Context) {
-        val lp = LauncherPrefs.get(context)
-        when {
-            LockedUserState.get(context).isUserUnlocked ||
-                !moveStartupDataToDeviceProtectedStorageIsEnabled -> {
-                /* No-Op */
-            }
-            lp.isStartupDataMigrated -> {
-                Log.d(TAG, "preloading start up data")
-                LauncherAppState.INSTANCE.get(context)
-            }
-            else -> {
-                Log.d(TAG, "queuing start up data migration to boot aware prefs")
-                LockedUserState.get(context).runOnUserUnlocked {
-                    lp.migrateStartupDataToDeviceProtectedStorage()
-                }
-            }
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/DesktopModeStatus.java b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
new file mode 100644
index 0000000..b1aae16
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
@@ -0,0 +1,58 @@
+/*
+ * 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.content.Context;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
+
+// TODO(b/335401172): Explore unifying logic across core and shell
+public class DesktopModeStatus {
+
+    /**
+     * Flag to indicate whether to restrict desktop mode to supported devices.
+     */
+    private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
+
+    /**
+     * Return {@code true} if desktop mode should be restricted to supported devices.
+     */
+    @VisibleForTesting
+    public static boolean enforceDeviceRestrictions() {
+        return ENFORCE_DEVICE_RESTRICTIONS;
+    }
+
+    /**
+     * Return {@code true} if the current device supports desktop mode.
+     */
+    @VisibleForTesting
+    public static boolean isDesktopModeSupported(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_isDesktopModeSupported);
+    }
+
+    /**
+     * Return {@code true} if desktop mode can be entered on the current device.
+     */
+    public static boolean canEnterDesktopMode(Context context) {
+        return Flags.enableDesktopWindowingMode()
+                && (!enforceDeviceRestrictions() || isDesktopModeSupported(context));
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index aa0f728..e33ef7f 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -23,13 +23,12 @@
 import com.android.launcher3.popup.SystemShortcut
 import com.android.quickstep.views.RecentsView
 import com.android.quickstep.views.RecentsViewContainer
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
-import com.android.window.flags.Flags
+import com.android.quickstep.views.TaskView.TaskContainer
 
 /** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
 class DesktopSystemShortcut(
     container: RecentsViewContainer,
-    private val mTaskContainer: TaskIdAttributeContainer,
+    private val mTaskContainer: TaskContainer,
     abstractFloatingViewHelper: AbstractFloatingViewHelper
 ) :
     SystemShortcut<RecentsViewContainer>(
@@ -52,7 +51,7 @@
     }
 
     companion object {
-        /** Creates a factory for creating Desktop system shorcuts. */
+        /** Creates a factory for creating Desktop system shortcuts. */
         @JvmOverloads
         fun createFactory(
             abstractFloatingViewHelper: AbstractFloatingViewHelper = AbstractFloatingViewHelper()
@@ -60,9 +59,9 @@
             return object : TaskShortcutFactory {
                 override fun getShortcuts(
                     container: RecentsViewContainer,
-                    taskContainer: TaskIdAttributeContainer
+                    taskContainer: TaskContainer
                 ): List<DesktopSystemShortcut>? {
-                    return if (!Flags.enableDesktopWindowingMode()) null
+                    return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
                     else if (!taskContainer.task.isDockable) null
                     else
                         listOf(
@@ -74,7 +73,7 @@
                         )
                 }
 
-                override fun showForSplitscreen() = true
+                override fun showForGroupedTask() = true
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
index 1cc54d8..0f844e1 100644
--- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -33,7 +33,7 @@
     val customLphThresholds =
         propReader.get(
             "CUSTOM_LPH_THRESHOLDS",
-            false,
+            true,
             "Server side control to customize LPH timeout and touch slop"
         )
 
@@ -154,7 +154,7 @@
     }
 
     companion object {
-        val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
+        @JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
 
         @JvmStatic fun get() = configHelper.config
     }
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 92cdf72..625b6c6 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -68,11 +68,12 @@
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.system.InputConsumerController;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
+import java.util.List;
 import java.util.UUID;
 import java.util.function.Consumer;
 
@@ -140,9 +141,13 @@
     }
 
     @Override
-    protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
-            long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
-            RemoteAnimationTarget runningTaskTarget) {
+    protected HomeAnimationFactory createHomeAnimationFactory(
+            List<IBinder> launchCookies,
+            long duration,
+            boolean isTargetTranslucent,
+            boolean appCanEnterPip,
+            RemoteAnimationTarget runningTaskTarget,
+            @Nullable TaskView targetTaskView) {
         mAppCanEnterPip = appCanEnterPip;
         if (appCanEnterPip) {
             return new FallbackPipToHomeAnimationFactory();
@@ -380,7 +385,7 @@
         }
 
         @Override
-        public void update(RectF currentRect, float progress, float radius) {
+        public void update(RectF currentRect, float progress, float radius, int overlayAlpha) {
             if (mSurfaceControl != null) {
                 currentRect.roundOut(mTempRect);
                 Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 6b33c0a..81c9d4a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -30,6 +30,7 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
 
 import android.content.Intent;
+import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 
@@ -182,9 +183,10 @@
     private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots;
 
     /** The time when the swipe up gesture is triggered. */
-    private long mSwipeUpStartTimeMs;
+    private final long mSwipeUpStartTimeMs = SystemClock.uptimeMillis();
 
     private boolean mHandlingAtomicEvent;
+    private boolean mIsInExtendedSlopRegion;
 
     public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
         mHomeIntent = componentObserver.getHomeIntent();
@@ -493,6 +495,25 @@
     }
 
     /**
+     * Set whether it's in long press nav handle (LPNH)'s extended touch slop region, e.g., second
+     * stage region in order to continue respect LPNH and ignore other touch slop logic.
+     * This will only be set to true when flag ENABLE_LPNH_TWO_STAGES is turned on.
+     */
+    public void setIsInExtendedSlopRegion(boolean isInExtendedSlopRegion) {
+        if (DeviceConfigWrapper.get().getEnableLpnhTwoStages()) {
+            mIsInExtendedSlopRegion = isInExtendedSlopRegion;
+        }
+    }
+
+    /**
+     * Returns whether it's in LPNH's extended touch slop region. This is only valid when flag
+     * ENABLE_LPNH_TWO_STAGES is turned on.
+     */
+    public boolean isInExtendedSlopRegion() {
+        return mIsInExtendedSlopRegion;
+    }
+
+    /**
      * Returns and clears the canceled animation thumbnail data. This call only returns a value
      * while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
      * calling {@link RecentsAnimationController#cleanupScreenshot()}.
@@ -508,21 +529,18 @@
         return null;
     }
 
-    void setSwipeUpStartTimeMs(long uptimeMs) {
-        mSwipeUpStartTimeMs = uptimeMs;
-    }
-
     long getSwipeUpStartTimeMs() {
         return mSwipeUpStartTimeMs;
     }
 
-    public void dump(PrintWriter pw) {
-        pw.println("GestureState:");
-        pw.println("  gestureID=" + mGestureId);
-        pw.println("  runningTask=" + mRunningTask);
-        pw.println("  endTarget=" + mEndTarget);
-        pw.println("  lastAppearedTaskTargetId=" + Arrays.toString(mLastAppearedTaskTargets));
-        pw.println("  lastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
-        pw.println("  isRecentsAnimationRunning=" + isRecentsAnimationRunning());
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "GestureState:");
+        pw.println(prefix + "\tgestureID=" + mGestureId);
+        pw.println(prefix + "\trunningTask=" + mRunningTask);
+        pw.println(prefix + "\tendTarget=" + mEndTarget);
+        pw.println(prefix + "\tlastAppearedTaskTargetId="
+                + Arrays.toString(mLastAppearedTaskTargets));
+        pw.println(prefix + "\tlastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
+        pw.println(prefix + "\tisRecentsAnimationRunning=" + isRecentsAnimationRunning());
     }
 }
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 79b09fd..225b127 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -220,6 +220,11 @@
                 }
             });
         }
+
+        @Override
+        public void setTriggerBack(boolean triggerBack) {
+            // TODO(b/261654570): track touch from the Launcher process.
+        }
     }
 
     private static class RemoteAnimationRunnerStub extends IRemoteAnimationRunner.Stub {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 6647057..6a9f509 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ObjectWrapper;
+import com.android.launcher3.views.ClipIconView;
 import com.android.launcher3.views.FloatingIconView;
 import com.android.launcher3.views.FloatingView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -55,7 +56,8 @@
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.system.InputConsumerController;
 
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Temporary class to allow easier refactoring
@@ -72,9 +74,13 @@
 
 
     @Override
-    protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
-            long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
-            RemoteAnimationTarget runningTaskTarget) {
+    protected HomeAnimationFactory createHomeAnimationFactory(
+            List<IBinder> launchCookies,
+            long duration,
+            boolean isTargetTranslucent,
+            boolean appCanEnterPip,
+            RemoteAnimationTarget runningTaskTarget,
+            @Nullable TaskView targetTaskView) {
         if (mContainer == null) {
             mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                     isPresent -> mRecentsView.startHome());
@@ -86,10 +92,19 @@
             };
         }
 
-        final View workspaceView = findWorkspaceView(launchCookies,
-                mRecentsView.getRunningTaskView());
-        boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow()
-                && workspaceView.getHeight() > 0;
+        TaskView sourceTaskView = mRecentsView == null && targetTaskView == null
+                ? null
+                : targetTaskView == null
+                        ? mRecentsView.getRunningTaskView()
+                        : targetTaskView;
+        final View workspaceView = findWorkspaceView(
+                targetTaskView == null ? launchCookies : Collections.emptyList(),
+                sourceTaskView);
+        boolean canUseWorkspaceView = workspaceView != null
+                && workspaceView.isAttachedToWindow()
+                && workspaceView.getHeight() > 0
+                && (mContainer.getDesktopVisibilityController() == null
+                || !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
 
         mContainer.getRootView().setForceHideBackArrow(true);
         if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
@@ -97,16 +112,24 @@
         }
 
         if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
-            return new LauncherHomeAnimationFactory();
+            return new LauncherHomeAnimationFactory() {
+
+                @Nullable
+                @Override
+                public TaskView getTargetTaskView() {
+                    return targetTaskView;
+                }
+            };
         }
         if (workspaceView instanceof LauncherAppWidgetHostView) {
             return createWidgetHomeAnimationFactory((LauncherAppWidgetHostView) workspaceView,
                     isTargetTranslucent, runningTaskTarget);
         }
-        return createIconHomeAnimationFactory(workspaceView);
+        return createIconHomeAnimationFactory(workspaceView, targetTaskView);
     }
 
-    private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
+    private HomeAnimationFactory createIconHomeAnimationFactory(
+            View workspaceView, @Nullable TaskView targetTaskView) {
         RectF iconLocation = new RectF();
         FloatingIconView floatingIconView = getFloatingIconView(mContainer, workspaceView, null,
                 mContainer.getTaskbarUIController() == null
@@ -119,6 +142,10 @@
         float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
 
         return new FloatingViewHomeAnimationFactory(floatingIconView) {
+            @Nullable
+            private RectF mTargetRect;
+            @Nullable
+            private RectFSpringAnim mSiblingAnimation;
 
             @Nullable
             @Override
@@ -135,22 +162,68 @@
             @NonNull
             @Override
             public RectF getWindowTargetRect() {
-                return iconLocation;
+                if (enableScalingRevealHomeAnimation()) {
+                    if (mTargetRect == null) {
+                        mTargetRect = new RectF(iconLocation);
+                    }
+                    return mTargetRect;
+                } else {
+                    return iconLocation;
+                }
+            }
+
+            @Override
+            public void playAtomicAnimation(float velocity) {
+                if (enableScalingRevealHomeAnimation()) {
+                    if (mContainer != null) {
+                        new ScalingWorkspaceRevealAnim(
+                                mContainer, mSiblingAnimation, getWindowTargetRect()).start();
+                    }
+                } else {
+                    super.playAtomicAnimation(velocity);
+                }
             }
 
             @Override
             public void setAnimation(RectFSpringAnim anim) {
                 super.setAnimation(anim);
-                anim.addAnimatorListener(floatingIconView);
-                floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
-                floatingIconView.setFastFinishRunnable(anim::end);
+                mSiblingAnimation = anim;
+                mSiblingAnimation.addAnimatorListener(floatingIconView);
+                floatingIconView.setOnTargetChangeListener(
+                        mSiblingAnimation::onTargetPositionChanged);
+                floatingIconView.setFastFinishRunnable(mSiblingAnimation::end);
             }
 
             @Override
-            public void update(RectF currentRect, float progress, float radius) {
-                super.update(currentRect, progress, radius);
+            public void update(
+                    RectF currentRect,
+                    float progress,
+                    float radius,
+                    int overlayAlpha) {
                 floatingIconView.update(1f /* alpha */, currentRect, progress, windowAlphaThreshold,
-                        radius, false);
+                        radius, false, overlayAlpha);
+            }
+
+            @Override
+            public boolean isAnimationReady() {
+                return floatingIconView.isLaidOut();
+            }
+
+            @Override
+            public void setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist) {
+                super.setTaskViewArtist(taskViewArtist);
+                floatingIconView.setOverlayArtist(taskViewArtist);
+            }
+
+            @Override
+            public boolean isAnimatingIntoIcon() {
+                return true;
+            }
+
+            @Nullable
+            @Override
+            public TaskView getTargetTaskView() {
+                return targetTaskView;
             }
         };
     }
@@ -204,8 +277,8 @@
             }
 
             @Override
-            public void update(RectF currentRect, float progress, float radius) {
-                super.update(currentRect, progress, radius);
+            public void update(RectF currentRect, float progress, float radius, int overlayAlpha) {
+                super.update(currentRect, progress, radius, overlayAlpha);
                 final float fallbackBackgroundAlpha =
                         1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
                 final float foregroundAlpha =
@@ -226,13 +299,14 @@
      * associated with the running task.
      */
     @Nullable
-    private View findWorkspaceView(ArrayList<IBinder> launchCookies, TaskView runningTaskView) {
+    private View findWorkspaceView(List<IBinder> launchCookies, TaskView sourceTaskView) {
         if (mIsSwipingPipToHome) {
             // Disable if swiping to PIP
             return null;
         }
-        if (runningTaskView == null || runningTaskView.getTask() == null
-                || runningTaskView.getTask().key.getComponent() == null) {
+        if (sourceTaskView == null
+                || sourceTaskView.getFirstTask() == null
+                || sourceTaskView.getFirstTask().key.getComponent() == null) {
             // Disable if it's an invalid task
             return null;
         }
@@ -249,8 +323,8 @@
         }
 
         return mContainer.getFirstMatchForAppClose(launchCookieItemId,
-                runningTaskView.getTask().key.getComponent().getPackageName(),
-                UserHandle.of(runningTaskView.getTask().key.userId),
+                sourceTaskView.getFirstTask().key.getComponent().getPackageName(),
+                UserHandle.of(sourceTaskView.getFirstTask().key.userId),
                 false /* supportsAllAppsState */);
     }
 
@@ -298,15 +372,9 @@
 
         @Override
         public void playAtomicAnimation(float velocity) {
-            if (enableScalingRevealHomeAnimation()) {
-                if (mContainer != null) {
-                    new ScalingWorkspaceRevealAnim(mContainer).start();
-                }
-            } else {
-                new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
-                        getViewIgnoredInWorkspaceRevealAnimation())
-                        .start();
-            }
+            new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
+                    getViewIgnoredInWorkspaceRevealAnimation())
+                    .start();
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 0a02e99..a71e314 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -109,6 +109,8 @@
      * Sets a listener for changes in {@link #isHomeAndOverviewSame()}
      */
     public void setOverviewChangeListener(Consumer<Boolean> overviewChangeListener) {
+        // TODO(b/337861962): This method should be able to support multiple listeners instead of
+        // one so that we can reuse the same instance of this class across multiple places
         mOverviewChangeListener = overviewChangeListener;
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 879fccb..711882c 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -97,6 +97,13 @@
                     RecentTasksList.this.onRunningTaskVanished(taskInfo);
                 });
             }
+
+            @Override
+            public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+                mMainThreadExecutor.execute(() -> {
+                    RecentTasksList.this.onRunningTaskChanged(taskInfo);
+                });
+            }
         });
         // We may receive onRunningTaskAppeared events later for tasks which have already been
         // included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
@@ -244,6 +251,20 @@
         }
     }
 
+    private void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        // Find the task from the list of running tasks, if it exists
+        for (ActivityManager.RunningTaskInfo existingTask : mRunningTasks) {
+            if (existingTask.taskId != taskInfo.taskId) continue;
+
+            mRunningTasks.remove(existingTask);
+            mRunningTasks.add(taskInfo);
+            if (mRunningTasksListener != null) {
+                mRunningTasksListener.onRunningTasksChanged();
+            }
+            return;
+        }
+    }
+
     /**
      * Loads and creates a list of all the recent tasks.
      */
@@ -390,4 +411,4 @@
             return mRequestId == requestId && (!mKeysOnly || loadKeysOnly);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 5d26ec0..da7a98f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -39,6 +39,7 @@
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -219,6 +220,13 @@
         }
     }
 
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RecentsAnimationCallbacks:");
+
+        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+        pw.println(prefix + "\tmCancelled=" + mCancelled);
+    }
+
     /**
      * Listener for the recents animation callbacks.
      */
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 06a442b..1b05e28 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -41,6 +41,7 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
+import java.io.PrintWriter;
 import java.util.function.Consumer;
 
 /**
@@ -267,4 +268,14 @@
     public boolean getFinishTargetIsLauncher() {
         return mFinishTargetIsLauncher;
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RecentsAnimationController:");
+
+        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+        pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
+        pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
+        pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
+        pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 4b4f914..54466f3 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,6 +33,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -399,7 +400,8 @@
                 && (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
                 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
                         || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
-                && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0;
+                && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0
+                && (mSystemUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) == 0;
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index f936882..82bb453 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -25,6 +25,8 @@
 import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
+import java.io.PrintWriter;
+
 /**
  * Extension of {@link RemoteAnimationTargets} with additional information about swipe
  * up animation
@@ -63,4 +65,14 @@
         }
         return false;
     }
+
+    @Override
+    public void dump(String prefix, PrintWriter pw) {
+        super.dump(prefix, pw);
+        prefix += '\t';
+        pw.println(prefix + "RecentsAnimationTargets:");
+
+        pw.println(prefix + "\thomeContentInsets=" + homeContentInsets);
+        pw.println(prefix + "\tminimizedHomeBounds=" + minimizedHomeBounds);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index e0c7403..57edd82 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -149,6 +150,14 @@
         }
     }
 
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RemoteAnimationTargets:");
+
+        pw.println(prefix + "\ttargetMode=" + targetMode);
+        pw.println(prefix + "\thasRecents=" + hasRecents);
+        pw.println(prefix + "\tmReleased=" + mReleased);
+    }
+
     /**
      * Interface for intercepting surface release method
      */
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 7f2aded..3dec381 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -222,8 +222,10 @@
 
         for (int i = 0; i < mRemoteTargetHandles.length; i++) {
             RemoteAnimationTarget primaryTaskTarget = targets.apps[i];
+            List<RemoteAnimationTarget> excludeTargets = Arrays.stream(targets.apps)
+                    .filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
             mRemoteTargetHandles[i].mTransformParams.setTargetSet(
-                    createRemoteAnimationTargetsForTaskId(targets, primaryTaskTarget.taskId));
+                    createRemoteAnimationTargetsForTarget(targets, excludeTargets));
             mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
         }
         return mRemoteTargetHandles;
@@ -290,33 +292,6 @@
     }
 
     /**
-     * Ensures that we only animate one specific app target. Includes ancillary targets such as
-     * home/recents
-     *
-     * @param targets remote animation targets to filter
-     * @param taskId  id for a task that we want this remote animation to apply to
-     * @return {@link RemoteAnimationTargets} where app target only includes the app that has the
-     * {@code taskId} that was passed in
-     */
-    private RemoteAnimationTargets createRemoteAnimationTargetsForTaskId(
-            RemoteAnimationTargets targets, int taskId) {
-        RemoteAnimationTarget[] targetApp = null;
-        for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) {
-            if (targetCompat.taskId == taskId) {
-                targetApp = new RemoteAnimationTarget[]{targetCompat};
-                break;
-            }
-        }
-
-        if (targetApp == null) {
-            targetApp = new RemoteAnimationTarget[0];
-        }
-
-        return new RemoteAnimationTargets(targetApp, targets.wallpapers, targets.nonApps,
-                targets.targetMode);
-    }
-
-    /**
      * The object returned by this is may be modified in
      * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)}, specifically the length of the
      * array may be shortened based on the number of RemoteAnimationTargets present.
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index bf50d70..3380291 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.NavigationMode;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -50,7 +51,7 @@
 /**
  * Helper class for transforming touch events
  */
-public class RotationTouchHelper implements DisplayInfoChangeListener {
+public class RotationTouchHelper implements DisplayInfoChangeListener, SafeCloseable {
 
     public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
             new MainThreadInitializedObject<>(RotationTouchHelper::new);
@@ -197,6 +198,11 @@
         mOnDestroyActions.add(action);
     }
 
+    @Override
+    public void close() {
+        destroy();
+    }
+
     /**
      * Cleans up all the registered listeners and receivers.
      */
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index f474796..29a57fc 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -24,22 +24,30 @@
 
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 
 public class SimpleOrientationTouchTransformer implements
-        DisplayController.DisplayInfoChangeListener {
+        DisplayController.DisplayInfoChangeListener, SafeCloseable {
 
     public static final MainThreadInitializedObject<SimpleOrientationTouchTransformer> INSTANCE =
             new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
 
+    private final Context mContext;
     private OrientationRectF mOrientationRectF;
 
     public SimpleOrientationTouchTransformer(Context context) {
+        mContext = context;
         DisplayController.INSTANCE.get(context).addChangeListener(this);
         onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
                 CHANGE_ALL);
     }
 
     @Override
+    public void close() {
+        DisplayController.INSTANCE.get(mContext).removeChangeListener(this);
+    }
+
+    @Override
     public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
         if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
             return;
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 5ff9787..fb54241 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -17,6 +17,7 @@
 
 import static com.android.app.animation.Interpolators.ACCELERATE_1_5;
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.PagedView.INVALID_PAGE;
 
 import android.animation.Animator;
 import android.content.Context;
@@ -27,6 +28,7 @@
 import android.view.RemoteAnimationTarget;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.DeviceProfile;
@@ -36,6 +38,7 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.views.ClipIconView;
 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -46,6 +49,8 @@
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 
 import java.util.Arrays;
 import java.util.function.Consumer;
@@ -201,7 +206,7 @@
 
         public void setAnimation(RectFSpringAnim anim) { }
 
-        public void update(RectF currentRect, float progress, float radius) { }
+        public void update(RectF currentRect, float progress, float radius, int overlayAlpha) { }
 
         public void onCancel() { }
 
@@ -222,6 +227,33 @@
             }
             return Utilities.mapToRange(progress, start, end, 1, 0, ACCELERATE_1_5);
         }
+
+        /**
+         * Sets a {@link com.android.launcher3.views.ClipIconView.TaskViewArtist} that should be
+         * used draw a {@link TaskView} during this home animation.
+         */
+        public void setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist) { }
+
+        public boolean isAnimationReady() {
+            return true;
+        }
+
+        public boolean isAnimatingIntoIcon() {
+            return false;
+        }
+
+        @Nullable
+        public TaskView getTargetTaskView() {
+            return null;
+        }
+
+        public boolean isRtl() {
+            return Utilities.isRtl(mContext.getResources());
+        }
+
+        public boolean isPortrait() {
+            return !mDp.isLandscape && !mDp.isSeascape();
+        }
     }
 
     /**
@@ -276,9 +308,13 @@
         for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length;
                 i < mRemoteTargetHandlesLength; i++) {
             RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i];
-            out[i] = getWindowAnimationToHomeInternal(homeAnimationFactory,
-                    targetRect, remoteHandle.getTransformParams(),
-                    remoteHandle.getTaskViewSimulator(), startRects[i], homeToWindowPositionMap[i]);
+            out[i] = getWindowAnimationToHomeInternal(
+                    homeAnimationFactory,
+                    targetRect,
+                    remoteHandle.getTransformParams(),
+                    remoteHandle.getTaskViewSimulator(),
+                    startRects[i],
+                    homeToWindowPositionMap[i]);
         }
         return out;
     }
@@ -288,21 +324,39 @@
     }
 
     private RectFSpringAnim getWindowAnimationToHomeInternal(
-            HomeAnimationFactory homeAnimationFactory, RectF targetRect,
-            TransformParams transformParams, TaskViewSimulator taskViewSimulator,
-            RectF startRect, Matrix homeToWindowPositionMap) {
+            HomeAnimationFactory homeAnimationFactory,
+            RectF targetRect,
+            TransformParams transformParams,
+            TaskViewSimulator taskViewSimulator,
+            RectF startRect,
+            Matrix homeToWindowPositionMap) {
         RectF cropRectF = new RectF(taskViewSimulator.getCurrentCropRect());
         // Move the startRect to Launcher space as floatingIconView runs in Launcher
         Matrix windowToHomePositionMap = new Matrix();
 
-        // If the start rect ends up overshooting too much to the left/right offscreen, bring it
-        // back to fullscreen. This can happen when the recentsScroll value isn't aligned with
-        // the pageScroll value for a given taskView, see b/228829958#comment12
-        mRemoteTargetHandles[0].getTaskViewSimulator().getOrientationState().getOrientationHandler()
-                .fixBoundsForHomeAnimStartRect(startRect, mDp);
+        TaskView targetTaskView = homeAnimationFactory.getTargetTaskView();
+        if (targetTaskView == null) {
+            // If the start rect ends up overshooting too much to the left/right offscreen, bring it
+            // back to fullscreen. This can happen when the recentsScroll value isn't aligned with
+            // the pageScroll value for a given taskView, see b/228829958#comment12
+            mRemoteTargetHandles[0].getTaskViewSimulator()
+                    .getOrientationState()
+                    .getOrientationHandler()
+                    .fixBoundsForHomeAnimStartRect(startRect, mDp);
 
+        }
         homeToWindowPositionMap.invert(windowToHomePositionMap);
         windowToHomePositionMap.mapRect(startRect);
+        RectF invariantStartRect = new RectF(startRect);
+
+        if (targetTaskView != null) {
+            Rect thumbnailBounds = new Rect();
+            targetTaskView.getThumbnailBounds(thumbnailBounds, /* relativeToDragLayer= */ true);
+
+            invariantStartRect = new RectF(thumbnailBounds);
+            invariantStartRect.offsetTo(startRect.left, thumbnailBounds.top);
+            startRect = new RectF(thumbnailBounds);
+        }
 
         boolean useTaskbarHotseatParams = mDp.isTaskbarPresent
                 && homeAnimationFactory.isInHotseat();
@@ -312,8 +366,12 @@
         homeAnimationFactory.setAnimation(anim);
 
         SpringAnimationRunner runner = new SpringAnimationRunner(
-                homeAnimationFactory, cropRectF, homeToWindowPositionMap,
-                transformParams, taskViewSimulator);
+                homeAnimationFactory,
+                cropRectF,
+                homeToWindowPositionMap,
+                transformParams,
+                taskViewSimulator,
+                invariantStartRect);
         anim.addAnimatorListener(runner);
         anim.addOnUpdateListener(runner);
         return anim;
@@ -336,9 +394,30 @@
         final float mStartRadius;
         final float mEndRadius;
 
-        SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
-                Matrix homeToWindowPositionMap, TransformParams transformParams,
-                TaskViewSimulator taskViewSimulator) {
+        final RectF mRunningTaskViewStartRectF;
+        @Nullable
+        final TaskView mTargetTaskView;
+        final float mRunningTaskViewScrollOffset;
+        final float mTaskViewWidth;
+        final float mTaskViewHeight;
+        final boolean mIsPortrait;
+        final Rect mThumbnailStartBounds = new Rect();
+
+        // Store the mTargetTaskView view properties onAnimationStart so that we can reset them
+        // when cleaning up.
+        float mTaskViewAlpha;
+        float mTaskViewTranslationX;
+        float mTaskViewTranslationY;
+        float mTaskViewScaleX;
+        float mTaskViewScaleY;
+
+        SpringAnimationRunner(
+                HomeAnimationFactory factory,
+                RectF cropRectF,
+                Matrix homeToWindowPositionMap,
+                TransformParams transformParams,
+                TaskViewSimulator taskViewSimulator,
+                RectF invariantStartRect) {
             mAnimationFactory = factory;
             mHomeAnim = factory.createActivityAnimationToHome();
             mCropRectF = cropRectF;
@@ -351,22 +430,62 @@
             // rounding at the end of the animation.
             mStartRadius = taskViewSimulator.getCurrentCornerRadius();
             mEndRadius = factory.getEndRadius(cropRectF);
+
+            mRunningTaskViewStartRectF = invariantStartRect;
+            mTargetTaskView = factory.getTargetTaskView();
+            mTaskViewWidth = mTargetTaskView == null ? 0 : mTargetTaskView.getWidth();
+            mTaskViewHeight = mTargetTaskView == null ? 0 : mTargetTaskView.getHeight();
+            mIsPortrait = factory.isPortrait();
+            // Use the running task's start position to determine how much it needs to be offset
+            // to end up offscreen.
+            mRunningTaskViewScrollOffset = factory.isRtl()
+                    ? (Math.min(0, -invariantStartRect.right))
+                    : (Math.max(0, mDp.widthPx - invariantStartRect.left));
         }
 
         @Override
         public void onUpdate(RectF currentRect, float progress) {
-            mHomeAnim.setPlayFraction(progress);
-            mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
-
-            mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
             float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
             float alpha = mAnimationFactory.getWindowAlpha(progress);
-            mLocalTransformParams
-                    .setTargetAlpha(alpha)
-                    .setCornerRadius(cornerRadius);
-            mLocalTransformParams.applySurfaceParams(mLocalTransformParams
-                    .createSurfaceParams(this));
-            mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
+
+            mHomeAnim.setPlayFraction(progress);
+            if (mTargetTaskView == null) {
+                mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
+                mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+                mLocalTransformParams
+                        .setTargetAlpha(alpha)
+                        .setCornerRadius(cornerRadius);
+            } else {
+                mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, mRunningTaskViewStartRectF);
+                mWindowCurrentRect.offset(mRunningTaskViewScrollOffset * progress, 0f);
+                mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+                mLocalTransformParams.setCornerRadius(mStartRadius);
+            }
+
+            mLocalTransformParams.applySurfaceParams(
+                    mLocalTransformParams.createSurfaceParams(this));
+            mAnimationFactory.update(
+                    currentRect, progress, mMatrix.mapRadius(cornerRadius), (int) (alpha * 255));
+
+            if (mTargetTaskView == null) {
+                return;
+            }
+            if (mAnimationFactory.isAnimatingIntoIcon() && mAnimationFactory.isAnimationReady()) {
+                mTargetTaskView.setAlpha(0f);
+                return;
+            }
+            mTargetTaskView.setAlpha(mAnimationFactory.isAnimatingIntoIcon() ? 1f : alpha);
+            float width = mThumbnailStartBounds.width();
+            float height =  mThumbnailStartBounds.height();
+            float scale = Math.min(currentRect.width(), currentRect.height())
+                    / Math.min(width, height);
+
+            mTargetTaskView.setScaleX(scale);
+            mTargetTaskView.setScaleY(scale);
+            mTargetTaskView.setTranslationX(
+                    currentRect.centerX() - mThumbnailStartBounds.centerX());
+            mTargetTaskView.setTranslationY(
+                    currentRect.centerY() - mThumbnailStartBounds.centerY());
         }
 
         @Override
@@ -379,16 +498,71 @@
 
         @Override
         public void onCancel() {
+            cleanUp();
             mAnimationFactory.onCancel();
         }
 
         @Override
         public void onAnimationStart(Animator animation) {
+            setUp();
             mHomeAnim.dispatchOnStart();
+            if (mTargetTaskView == null) {
+                return;
+            }
+            Rect thumbnailBounds = new Rect();
+            // Use bounds relative to mTargetTaskView since it will be scaled afterwards
+            mTargetTaskView.getThumbnailBounds(thumbnailBounds);
+            mAnimationFactory.setTaskViewArtist(new ClipIconView.TaskViewArtist(
+                    mTargetTaskView::draw,
+                    0f,
+                    -thumbnailBounds.top,
+                    Math.min(mTaskViewHeight, mTaskViewWidth),
+                    mIsPortrait));
+        }
+
+        private void setUp() {
+            if (mTargetTaskView == null) {
+                return;
+            }
+            RecentsView recentsView = mTargetTaskView.getRecentsView();
+            if (recentsView != null) {
+                recentsView.setOffsetMidpointIndexOverride(
+                        recentsView.indexOfChild(mTargetTaskView));
+            }
+            mTargetTaskView.getThumbnailBounds(
+                    mThumbnailStartBounds, /* relativeToDragLayer= */ true);
+            mTaskViewAlpha = mTargetTaskView.getAlpha();
+            if (mAnimationFactory.isAnimatingIntoIcon()) {
+                return;
+            }
+            mTaskViewTranslationX = mTargetTaskView.getTranslationX();
+            mTaskViewTranslationY = mTargetTaskView.getTranslationY();
+            mTaskViewScaleX = mTargetTaskView.getScaleX();
+            mTaskViewScaleY = mTargetTaskView.getScaleY();
+        }
+
+        private void cleanUp() {
+            if (mTargetTaskView == null) {
+                return;
+            }
+            RecentsView recentsView = mTargetTaskView.getRecentsView();
+            if (recentsView != null) {
+                recentsView.setOffsetMidpointIndexOverride(INVALID_PAGE);
+            }
+            mTargetTaskView.setAlpha(mTaskViewAlpha);
+            if (!mAnimationFactory.isAnimatingIntoIcon()) {
+                mTargetTaskView.setTranslationX(mTaskViewTranslationX);
+                mTargetTaskView.setTranslationY(mTaskViewTranslationY);
+                mTargetTaskView.setScaleX(mTaskViewScaleX);
+                mTargetTaskView.setScaleY(mTaskViewScaleY);
+                return;
+            }
+            mAnimationFactory.setTaskViewArtist(null);
         }
 
         @Override
         public void onAnimationSuccess(Animator animator) {
+            cleanUp();
             mHomeAnim.getAnimationPlayer().end();
         }
     }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 30bb863..4d3fe41 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -23,6 +23,8 @@
 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.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -32,7 +34,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -65,6 +66,7 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AssistUtils;
 import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
@@ -108,8 +110,8 @@
 /**
  * Holds the reference to SystemUI.
  */
-public class SystemUiProxy implements ISystemUiProxy, NavHandle {
-    private static final String TAG = SystemUiProxy.class.getSimpleName();
+public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
+    private static final String TAG = "SystemUiProxy";
 
     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
             new MainThreadInitializedObject<>(SystemUiProxy::new);
@@ -199,6 +201,9 @@
     }
 
     @Override
+    public void close() { }
+
+    @Override
     public void onBackPressed() {
         if (mSystemUiProxy != null) {
             try {
@@ -454,10 +459,11 @@
     }
 
     @Override
-    public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+    public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier,
+            boolean haptic) {
         if (mSystemUiProxy != null) {
             try {
-                mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier);
+                mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call setOverrideHomeButtonLongPress", e);
             }
@@ -794,15 +800,29 @@
     /**
      * Tells SysUI when the bubble is being dragged.
      * Should be called only when the bubble bar is expanded.
-     * @param bubbleKey the key of the bubble to collapse/expand
-     * @param isBeingDragged whether the bubble is being dragged
+     * @param bubbleKey key of the bubble being dragged
      */
-    public void onBubbleDrag(@Nullable String bubbleKey, boolean isBeingDragged) {
+    public void startBubbleDrag(@Nullable String bubbleKey) {
         if (mBubbles == null) return;
         try {
-            mBubbles.onBubbleDrag(bubbleKey, isBeingDragged);
+            mBubbles.startBubbleDrag(bubbleKey);
         } catch (RemoteException e) {
-            Log.w(TAG, "Failed call onBubbleDrag");
+            Log.w(TAG, "Failed call startBubbleDrag");
+        }
+    }
+
+    /**
+     * Tells SysUI when the bubble stops being dragged.
+     * Should be called only when the bubble bar is expanded.
+     * @param bubbleKey key of the bubble being dragged
+     * @param location location of the bubble bar
+     */
+    public void stopBubbleDrag(@Nullable String bubbleKey, BubbleBarLocation location) {
+        if (mBubbles == null) return;
+        try {
+            mBubbles.stopBubbleDrag(bubbleKey, location);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call stopBubbleDrag");
         }
     }
 
@@ -1366,8 +1386,7 @@
      * Gets the set of running tasks.
      */
     public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
-        if (mRecentTasks != null
-                && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
+        if (mRecentTasks != null && shouldEnableRunningTasksForDesktopMode()) {
             try {
                 return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
             } catch (RemoteException e) {
@@ -1377,6 +1396,11 @@
         return new ArrayList<>();
     }
 
+    private boolean shouldEnableRunningTasksForDesktopMode() {
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
+    }
+
     private boolean handleMessageAsync(Message msg) {
         switch (msg.what) {
             case MSG_SET_SHELF_HEIGHT:
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 3b1ed46..2348f28 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,6 +17,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
 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;
@@ -49,14 +50,15 @@
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
+import java.io.PrintWriter;
 import java.util.HashMap;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
-    public static final boolean ENABLE_SHELL_TRANSITIONS =
-            SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
+    public static final boolean ENABLE_SHELL_TRANSITIONS = true;
     public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
             && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
 
+    private final Context mCtx;
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
     private RecentsAnimationTargets mTargets;
@@ -64,9 +66,9 @@
     private GestureState mLastGestureState;
     private RemoteAnimationTarget[] mLastAppearedTaskTargets;
     private Runnable mLiveTileCleanUpHandler;
-    private Context mCtx;
 
     private boolean mRecentsAnimationStartPending = false;
+    private boolean mShouldIgnoreMotionEvents = false;
 
     private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
         @Override
@@ -103,8 +105,16 @@
                 .startRecentsActivity(intent, 0, null, null, null));
     }
 
-    public boolean isRecentsAnimationStartPending() {
-        return mRecentsAnimationStartPending;
+    boolean shouldIgnoreMotionEvents() {
+        return mShouldIgnoreMotionEvents;
+    }
+
+    void notifyNewGestureStart() {
+        // If mRecentsAnimationStartPending is true at the beginning of a gesture, block all motion
+        // events for this new gesture so that this new gesture does not interfere with the
+        // previously-requested recents animation. Otherwise, clean up mShouldIgnoreMotionEvents.
+        // NOTE: this can lead to misleading logs
+        mShouldIgnoreMotionEvents = mRecentsAnimationStartPending;
     }
 
     /**
@@ -145,7 +155,12 @@
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
                     RecentsAnimationTargets targets) {
-                mRecentsAnimationStartPending = false;
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation(onRecentsAnimationStart): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 if (mCallbacks == null) {
                     // It's possible for the recents animation to have finished and be cleaned up
                     // by the time we process the start callback, and in that case, just we can skip
@@ -186,13 +201,25 @@
 
             @Override
             public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
-                mRecentsAnimationStartPending = false;
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation")
+                            .append("(onRecentsAnimationCanceled): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 cleanUpRecentsAnimation(newCallbacks);
             }
 
             @Override
             public void onRecentsAnimationFinished(RecentsAnimationController controller) {
-                mRecentsAnimationStartPending = false;
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation")
+                            .append("(onRecentsAnimationFinished): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 cleanUpRecentsAnimation(newCallbacks);
             }
 
@@ -301,15 +328,31 @@
                 options.setTransientLaunch();
             }
             options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
-            mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
+            mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx)
                     .startRecentsActivity(intent, options, mCallbacks);
+            if (enableHandleDelayedGestureCallbacks()) {
+                ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                        "TaskAnimationManager.startRecentsAnimation(shell transition path): ")
+                        .append("Setting mRecentsAnimationStartPending = ")
+                        .append(mRecentsAnimationStartPending));
+            }
         } else {
             UI_HELPER_EXECUTOR.execute(
                     () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
                             intent,
                             eventTime,
                             mCallbacks,
-                            result -> mRecentsAnimationStartPending = result,
+                            result -> {
+                                if (enableHandleDelayedGestureCallbacks()) {
+                                    ActiveGestureLog.INSTANCE.addLog(
+                                            new ActiveGestureLog.CompoundString(
+                                                    "TaskAnimationManager.startRecentsAnimation")
+                                                    .append("(legacy path): Setting ")
+                                                    .append("mRecentsAnimationStartPending = ")
+                                                    .append(result));
+                                }
+                                mRecentsAnimationStartPending = result;
+                            },
                             MAIN_EXECUTOR.getHandler()));
         }
         gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
@@ -439,7 +482,24 @@
         return mCallbacks;
     }
 
-    public void dump() {
-        // TODO
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "TaskAnimationManager:");
+
+        if (enableHandleDelayedGestureCallbacks()) {
+            pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending);
+            pw.println(prefix + "\tmShouldIgnoreUpcomingGestures=" + mShouldIgnoreMotionEvents);
+        }
+        if (mController != null) {
+            mController.dump(prefix + '\t', pw);
+        }
+        if (mCallbacks != null) {
+            mCallbacks.dump(prefix + '\t', pw);
+        }
+        if (mTargets != null) {
+            mTargets.dump(prefix + '\t', pw);
+        }
+        if (mLastGestureState != null) {
+            mLastGestureState.dump(prefix + '\t', pw);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 18b8e3e..1a46fb6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -16,8 +16,6 @@
 
 package com.android.quickstep;
 
-import static android.view.Surface.ROTATION_0;
-
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
 
@@ -33,7 +31,6 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.BaseActivity;
-import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -42,13 +39,14 @@
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.Snackbar;
 import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -61,13 +59,15 @@
 public class TaskOverlayFactory implements ResourceBasedOverride {
 
     public static List<SystemShortcut> getEnabledShortcuts(TaskView taskView,
-            TaskIdAttributeContainer taskContainer) {
+            TaskContainer taskContainer) {
         final ArrayList<SystemShortcut> shortcuts = new ArrayList<>();
         final RecentsViewContainer container =
                 RecentsViewContainer.containerFromContext(taskView.getContext());
-        boolean hasMultipleTasks = taskView.getTaskIds()[1] != -1;
         for (TaskShortcutFactory menuOption : MENU_OPTIONS) {
-            if (hasMultipleTasks && !menuOption.showForSplitscreen()) {
+            if (taskView instanceof GroupedTaskView && !menuOption.showForGroupedTask()) {
+                continue;
+            }
+            if (taskView instanceof DesktopTaskView && !menuOption.showForDesktopTask()) {
                 continue;
             }
 
@@ -77,37 +77,10 @@
             }
             shortcuts.addAll(menuShortcuts);
         }
-        RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState();
-        boolean canLauncherRotate = orientedState.isRecentsActivityRotationAllowed();
-        boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
-        boolean isTablet = container.getDeviceProfile().isTablet;
-
-        boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
-        // Add overview actions to the menu when:
-        // - single task is showing
-        // - in in-place rotate landscape mode, or in grid-only overview.
-        if (!hasMultipleTasks && ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview)) {
-            // Add screenshot action to task menu.
-            List<SystemShortcut> screenshotShortcuts = TaskShortcutFactory.SCREENSHOT
-                    .getShortcuts(container, taskContainer);
-            if (screenshotShortcuts != null) {
-                shortcuts.addAll(screenshotShortcuts);
-            }
-
-            // Add modal action only if display orientation is the same as the device orientation,
-            // or in grid-only overview.
-            if (orientedState.getDisplayRotation() == ROTATION_0 || isGridOnlyOverview) {
-                List<SystemShortcut> modalShortcuts = TaskShortcutFactory.MODAL
-                        .getShortcuts(container, taskContainer);
-                if (modalShortcuts != null) {
-                    shortcuts.addAll(modalShortcuts);
-                }
-            }
-        }
         return shortcuts;
     }
 
-    public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
+    public TaskOverlay createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
         return new TaskOverlay(thumbnailView);
     }
 
@@ -140,7 +113,9 @@
             TaskShortcutFactory.FREE_FORM,
             DesktopSystemShortcut.Companion.createFactory(),
             TaskShortcutFactory.WELLBEING,
-            TaskShortcutFactory.SAVE_APP_PAIR
+            TaskShortcutFactory.SAVE_APP_PAIR,
+            TaskShortcutFactory.SCREENSHOT,
+            TaskShortcutFactory.MODAL
     };
 
     /**
@@ -149,14 +124,14 @@
     public static class TaskOverlay<T extends OverviewActionsView> {
 
         protected final Context mApplicationContext;
-        protected final TaskThumbnailView mThumbnailView;
+        protected final TaskThumbnailViewDeprecated mThumbnailView;
 
         private T mActionsView;
         protected ImageActionsApi mImageApi;
 
-        protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
-            mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
-            mThumbnailView = taskThumbnailView;
+        protected TaskOverlay(TaskThumbnailViewDeprecated taskThumbnailViewDeprecated) {
+            mApplicationContext = taskThumbnailViewDeprecated.getContext().getApplicationContext();
+            mThumbnailView = taskThumbnailViewDeprecated;
             mImageApi = new ImageActionsApi(
                     mApplicationContext, mThumbnailView::getThumbnail);
         }
@@ -169,7 +144,7 @@
             return mActionsView;
         }
 
-        public TaskThumbnailView getThumbnailView() {
+        public TaskThumbnailViewDeprecated getThumbnailView() {
             return mThumbnailView;
         }
 
@@ -317,7 +292,7 @@
 
             @Override
             public void onClick(View view) {
-                saveScreenshot(mThumbnailView.getTaskView().getTask());
+                saveScreenshot(mThumbnailView.getTaskView().getFirstTask());
                 dismissTaskMenuView();
             }
         }
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 9d10ac1..a53d91f 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.view.Surface.ROTATION_0;
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
 import static com.android.window.flags.Flags.enableDesktopWindowingMode;
@@ -39,6 +40,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
@@ -50,19 +52,19 @@
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
@@ -75,11 +77,21 @@
 public interface TaskShortcutFactory {
     @Nullable
     default List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-            TaskIdAttributeContainer taskContainer) {
+            TaskContainer taskContainer) {
         return null;
     }
 
-    default boolean showForSplitscreen() {
+    /**
+     * Returns {@code true} if it should be shown for grouped task; {@code false} otherwise.
+     */
+    default boolean showForGroupedTask() {
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if it should be shown for desktop task; {@code false} otherwise.
+     */
+    default boolean showForDesktopTask() {
         return false;
     }
 
@@ -95,7 +107,7 @@
     TaskShortcutFactory APP_INFO = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             TaskView taskView = taskContainer.getTaskView();
             AppInfo.SplitAccessibilityInfo accessibilityInfo =
                     new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
@@ -107,7 +119,7 @@
         }
 
         @Override
-        public boolean showForSplitscreen() {
+        public boolean showForGroupedTask() {
             return true;
         }
     };
@@ -158,12 +170,12 @@
         private Handler mHandler;
 
         private final RecentsView mRecentsView;
-        private final TaskThumbnailView mThumbnailView;
+        private final TaskThumbnailViewDeprecated mThumbnailView;
         private final TaskView mTaskView;
         private final LauncherEvent mLauncherEvent;
 
         public FreeformSystemShortcut(int iconRes, int textRes, RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer, LauncherEvent launcherEvent) {
+                TaskContainer taskContainer, LauncherEvent launcherEvent) {
             super(iconRes, textRes, container, taskContainer.getItemInfo(),
                     taskContainer.getTaskView());
             mLauncherEvent = launcherEvent;
@@ -186,7 +198,7 @@
         }
 
         private void startActivity() {
-            final Task.TaskKey taskKey = mTaskView.getTask().key;
+            final Task.TaskKey taskKey = mTaskView.getFirstTask().key;
             final int taskId = taskKey.id;
             final ActivityOptions options = makeLaunchOptions(mTarget);
             if (options != null) {
@@ -279,7 +291,7 @@
     TaskShortcutFactory SPLIT_SELECT = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             DeviceProfile deviceProfile = container.getDeviceProfile();
             final Task task = taskContainer.getTask();
             final int intentFlags = task.key.baseIntent.getFlags();
@@ -314,7 +326,7 @@
         @Nullable
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             DeviceProfile deviceProfile = container.getDeviceProfile();
             final TaskView taskView = taskContainer.getTaskView();
             final RecentsView recentsView = taskView.getRecentsView();
@@ -323,24 +335,15 @@
                     recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
             boolean shouldShowActionsButtonInstead =
                     isLargeTileFocusedTask && isInExpectedScrollPosition;
-            boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskIdAttributeContainers())
-                    .anyMatch(att -> att != null && att.getItemInfo() != null
-                            && ((att.getItemInfo().runtimeStatusFlags
-                                & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
 
             // No "save app pair" menu item if:
-            // - app pairs feature is not enabled
             // - we are in 3p launcher
-            // - the task in question is a single task
-            // - at least one app in app pair is unpinnable
             // - the Overview Actions Button should be visible
-            // - the task is not a GroupedTaskView
-            if (!FeatureFlags.enableAppPairs()
-                    || !recentsView.supportsAppPairs()
-                    || !taskView.containsMultipleTasks()
-                    || hasUnpinnableApp
+            // - the task view is not a valid save-able split pair
+            if (!recentsView.supportsAppPairs()
                     || shouldShowActionsButtonInstead
-                    || !(taskView instanceof GroupedTaskView)) {
+                    || !recentsView.getSplitSelectController().getAppPairsController()
+                            .canSaveAppPair(taskView)) {
                 return null;
             }
 
@@ -354,7 +357,7 @@
         }
 
         @Override
-        public boolean showForSplitscreen() {
+        public boolean showForGroupedTask() {
             return true;
         }
     };
@@ -362,7 +365,7 @@
     TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             final Task task = taskContainer.getTask();
             if (!task.isDockable) {
                 return null;
@@ -388,7 +391,7 @@
     TaskShortcutFactory PIN = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             if (!SystemUiProxy.INSTANCE.get(container.asContext()).isActive()) {
                 return null;
             }
@@ -410,7 +413,7 @@
         private final TaskView mTaskView;
 
         public PinSystemShortcut(RecentsViewContainer target,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             super(R.drawable.ic_pin, R.string.recent_task_option_pin, target,
                     taskContainer.getItemInfo(), taskContainer.getTaskView());
             mTaskView = taskContainer.getTaskView();
@@ -420,7 +423,7 @@
         public void onClick(View view) {
             if (mTaskView.launchTaskAnimated() != null) {
                 SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
-                        mTaskView.getTask().key.id);
+                        mTaskView.getFirstTask().key.id);
             }
             dismissTaskMenuView();
             mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo())
@@ -431,7 +434,7 @@
     TaskShortcutFactory INSTALL = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             Task t = taskContainer.getTask();
             return InstantAppResolver.newInstance(container.asContext()).isInstantApp(
                     t.getTopComponent().getPackageName(), t.getKey().userId)
@@ -444,7 +447,7 @@
     TaskShortcutFactory WELLBEING = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
             SystemShortcut<ActivityContext> wellbeingShortcut =
                     WellbeingModel.SHORTCUT_FACTORY.getShortcut(container,
                             taskContainer.getItemInfo(), taskContainer.getTaskView());
@@ -455,19 +458,54 @@
     TaskShortcutFactory SCREENSHOT = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
+            boolean isTablet = container.getDeviceProfile().isTablet;
+            boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
+            // Extra conditions if it's not grid-only overview
+            if (!isGridOnlyOverview) {
+                RecentsOrientedState orientedState =
+                        taskContainer.getTaskView().getRecentsView().getPagedViewOrientedState();
+                boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
+                        && orientedState.getTouchRotation() != ROTATION_0;
+                if (!isFakeLandscape) {
+                    return null;
+                }
+            }
+
             SystemShortcut screenshotShortcut =
                     taskContainer.getThumbnailView().getTaskOverlay()
                             .getScreenshotShortcut(container, taskContainer.getItemInfo(),
                                     taskContainer.getTaskView());
             return createSingletonShortcutList(screenshotShortcut);
         }
+
+        @Override
+        public boolean showForDesktopTask() {
+            return true;
+        }
     };
 
     TaskShortcutFactory MODAL = new TaskShortcutFactory() {
         @Override
         public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
-                TaskIdAttributeContainer taskContainer) {
+                TaskContainer taskContainer) {
+            boolean isTablet = container.getDeviceProfile().isTablet;
+            boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
+            // Extra conditions if it's not grid-only overview
+            if (!isGridOnlyOverview) {
+                RecentsOrientedState orientedState =
+                        taskContainer.getTaskView().getRecentsView().getPagedViewOrientedState();
+                boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
+                        && orientedState.getTouchRotation() != ROTATION_0;
+                if (!isFakeLandscape) {
+                    return null;
+                }
+                // Disallow "Select" when swiping up from landscape due to rotated thumbnail.
+                if (orientedState.getDisplayRotation() != ROTATION_0) {
+                    return null;
+                }
+            }
+
             SystemShortcut modalStateSystemShortcut =
                     taskContainer.getThumbnailView().getTaskOverlay()
                             .getModalStateSystemShortcut(
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 80a449b..63e536a 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -70,7 +70,7 @@
             return "";
         }
         UserHandle user = UserHandle.of(userId);
-        ApplicationInfo applicationInfo = new PackageManagerHelper(context)
+        ApplicationInfo applicationInfo = PackageManagerHelper.INSTANCE.get(context)
                 .getApplicationInfo(packageName, user, 0);
         if (applicationInfo == null) {
             Log.e(TAG, "Failed to get title for userId=" + userId + ", packageName=" + packageName);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 450e960..d2560e6 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -80,7 +80,7 @@
 import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.animation.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.recents.model.Task;
@@ -121,7 +121,7 @@
                 for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
                     TaskView taskView = recentsView.getTaskViewAt(i);
                     if (recentsView.isTaskViewVisible(taskView)) {
-                        Task.TaskKey key = taskView.getTask().key;
+                        Task.TaskKey key = taskView.getFirstTask().key;
                         if (componentName.equals(key.getComponent()) && userId == key.userId) {
                             return taskView;
                         }
@@ -334,7 +334,7 @@
             // During animation we apply transformation on the thumbnailView (and not the rootView)
             // to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
             //    Mt K(0)` K(t) Mt`
-            TaskThumbnailView[] thumbnails = v.getThumbnails();
+            TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnailViews();
 
             // In case simulator copies and thumbnail size do no match, ensure we get the lesser.
             // This ensures we do not create arrays with empty elements or attempt to references
@@ -344,7 +344,7 @@
             Matrix[] mt = new Matrix[matrixSize];
             Matrix[] mti = new Matrix[matrixSize];
             for (int i = 0; i < matrixSize; i++) {
-                TaskThumbnailView ttv = thumbnails[i];
+                TaskThumbnailViewDeprecated ttv = thumbnails[i];
                 RectF localBounds = new RectF(0, 0,  ttv.getWidth(), ttv.getHeight());
                 float[] tvBoundsMapped = new float[]{0, 0,  ttv.getWidth(), ttv.getHeight()};
                 getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
@@ -391,7 +391,7 @@
             out.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    for (TaskThumbnailView ttv : thumbnails) {
+                    for (TaskThumbnailViewDeprecated ttv : thumbnails) {
                         ttv.setAnimationMatrix(null);
                     }
                 }
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index a2a6dde..3a6b804 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -34,6 +34,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitStageInfo;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -57,7 +58,8 @@
  * This class tracked the top-most task and  some 'approximate' task history to allow faster
  * system state estimation during touch interaction
  */
-public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
+public class TopTaskTracker extends ISplitScreenListener.Stub
+        implements TaskStackChangeListener, SafeCloseable {
 
     public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
             new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -67,12 +69,13 @@
     // Ordered list with first item being the most recent task.
     private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
 
-
+    private final Context mContext;
     private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
     private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
     private int mPinnedTaskId = INVALID_TASK_ID;
 
     private TopTaskTracker(Context context) {
+        mContext = context;
         mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
         mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
 
@@ -81,6 +84,12 @@
     }
 
     @Override
+    public void close() {
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
+        SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
+    }
+
+    @Override
     public void onTaskRemoved(int taskId) {
         mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 6635ee4..f94a29c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -24,6 +24,7 @@
 import static android.view.MotionEvent.ACTION_UP;
 
 import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
 import static com.android.launcher3.Flags.useActivityOverlay;
 import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
 import static com.android.launcher3.LauncherPrefs.backedUpItem;
@@ -41,6 +42,7 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENTS_ANIMATION_START_PENDING;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
@@ -92,6 +94,7 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -468,6 +471,18 @@
 
     private final ScreenOnTracker.ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
 
+    private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
+        @Override
+        public void onNavigateHome() {
+            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+        }
+
+        @Override
+        public void onToggleOverview() {
+            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+        }
+    };
+
     private ActivityManagerWrapper mAM;
     private OverviewCommandHelper mOverviewCommandHelper;
     private OverviewComponentObserver mOverviewComponentObserver;
@@ -498,10 +513,9 @@
         mDeviceState = new RecentsAnimationDeviceState(this, true);
         mAllAppsActionManager = new AllAppsActionManager(
                 this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
-        mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
+        mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
-        BootAwarePreloader.start(this);
 
         // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
         LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
@@ -716,16 +730,22 @@
         boolean isHoverActionWithoutConsumer = enableCursorHoverStates()
                 && isHoverActionWithoutConsumer(event);
 
-        // TODO(b/285636175): Uncomment this once WM can properly guarantee all animation callbacks
-//        if (mTaskAnimationManager.isRecentsAnimationStartPending()
-//                && (action == ACTION_DOWN || isHoverActionWithoutConsumer)) {
-//            ActiveGestureLog.INSTANCE.addLog(
-//                    new CompoundString("TIS.onInputEvent: ")
-//                            .append("Cannot process input event: a recents animation has been ")
-//                            .append("requested, but hasn't started."),
-//                    RECENTS_ANIMATION_START_PENDING);
-//            return;
-//        }
+        if (enableHandleDelayedGestureCallbacks()) {
+            if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+                mTaskAnimationManager.notifyNewGestureStart();
+            }
+            if (mTaskAnimationManager.shouldIgnoreMotionEvents()) {
+                if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+                    ActiveGestureLog.INSTANCE.addLog(
+                            new CompoundString("TIS.onMotionEvent: A new gesture has been ")
+                                    .append("started, but a previously-requested recents ")
+                                    .append("animation hasn't started. Ignoring all following ")
+                                    .append("motion events."),
+                            RECENTS_ANIMATION_START_PENDING);
+                }
+                return;
+            }
+        }
 
         SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
 
@@ -751,7 +771,6 @@
                 GestureState prevGestureState = new GestureState(mGestureState);
                 GestureState newGestureState = createGestureState(mGestureState,
                         getTrackpadGestureType(event));
-                newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis());
                 mConsumer.onConsumerAboutToBeSwitched();
                 mGestureState = newGestureState;
                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
@@ -999,7 +1018,7 @@
                             .append("TaskbarActivityContext != null, ")
                             .append("using TaskbarUnstashInputConsumer");
                     base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
-                            mOverviewCommandHelper);
+                            mOverviewCommandHelper, mGestureState);
                 }
             }
             if (enableBubblesLongPressNavHandle()) {
@@ -1027,7 +1046,7 @@
                 }
                 reasonString.append("using NavHandleLongPressInputConsumer");
                 base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
-                        mDeviceState, navHandle);
+                        mDeviceState, navHandle, mGestureState);
             }
 
             if (!enableBubblesLongPressNavHandle()) {
@@ -1431,28 +1450,31 @@
             mOverviewCommandHelper.dump(pw);
         }
         if (mGestureState != null) {
-            mGestureState.dump(pw);
+            mGestureState.dump("", pw);
         }
         pw.println("Input state:");
-        pw.println("  mInputMonitorCompat=" + mInputMonitorCompat);
-        pw.println("  mInputEventReceiver=" + mInputEventReceiver);
+        pw.println("\tmInputMonitorCompat=" + mInputMonitorCompat);
+        pw.println("\tmInputEventReceiver=" + mInputEventReceiver);
         DisplayController.INSTANCE.get(this).dump(pw);
         pw.println("TouchState:");
         BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
                 : mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
         boolean resumed = mOverviewComponentObserver != null
                 && mOverviewComponentObserver.getActivityInterface().isResumed();
-        pw.println("  createdOverviewActivity=" + createdOverviewActivity);
-        pw.println("  resumed=" + resumed);
-        pw.println("  mConsumer=" + mConsumer.getName());
+        pw.println("\tcreatedOverviewActivity=" + createdOverviewActivity);
+        pw.println("\tresumed=" + resumed);
+        pw.println("\tmConsumer=" + mConsumer.getName());
         ActiveGestureLog.INSTANCE.dump("", pw);
         RecentsModel.INSTANCE.get(this).dump("", pw);
+        if (mTaskAnimationManager != null) {
+            mTaskAnimationManager.dump("", pw);
+        }
         if (createdOverviewActivity != null) {
             createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
         }
         mTaskbarManager.dumpLogs("", pw);
         pw.println("AssistStateManager:");
-        AssistStateManager.INSTANCE.get(this).dump("  ", pw);
+        AssistStateManager.INSTANCE.get(this).dump("\t", pw);
         SystemUiProxy.INSTANCE.get(this).dump(pw);
         DeviceConfigWrapper.get().dump("   ", pw);
     }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 2e76356..1bf129c 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -46,12 +46,10 @@
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.views.ClearAllButton;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * State controller for fallback recents activity
@@ -98,8 +96,8 @@
         setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
                 clearAllButtonAlpha, LINEAR);
         float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
-        setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
-                MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR);
+        setter.setFloat(mActivity.getActionsView().getVisibilityAlphaSetter(),
+                OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, LINEAR);
 
         float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
         setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index d881a1f..b79586b 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -53,6 +53,7 @@
 import com.android.systemui.shared.recents.model.Task;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
         implements StateListener<RecentsState> {
@@ -144,8 +145,9 @@
     @Override
     public void setCurrentTask(int runningTaskViewId) {
         super.setCurrentTask(runningTaskViewId);
-        int runningTaskId = getTaskIdsForRunningTaskView()[0];
-        if (mHomeTask != null && mHomeTask.key.id != runningTaskId) {
+        int[] runningTaskIds = getTaskIdsForRunningTaskView();
+        if (mHomeTask != null
+                && Arrays.stream(runningTaskIds).noneMatch(taskId -> taskId == mHomeTask.key.id)) {
             mHomeTask = null;
             setRunningTaskHidden(false);
         }
@@ -182,13 +184,14 @@
         // as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
         // track the index of the next task appropriately, as if we are switching on any other app.
         // TODO(b/195607777) Confirm home task info is front-most task and not mixed in with others
-        int runningTaskId = getTaskIdsForRunningTaskView()[0];
-        if (mHomeTask != null && mHomeTask.key.id == runningTaskId
+        int[] runningTaskIds = getTaskIdsForRunningTaskView();
+        if (mHomeTask != null
+                && Arrays.stream(runningTaskIds).allMatch(taskId -> taskId == mHomeTask.key.id)
                 && !taskGroups.isEmpty()) {
             // Check if the task list has running task
             boolean found = false;
             for (GroupTask group : taskGroups) {
-                if (group.containsTask(runningTaskId)) {
+                if (Arrays.stream(runningTaskIds).allMatch(group::containsTask)) {
                     found = true;
                     break;
                 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 075e539..848a43a 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -31,6 +31,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.DeviceConfigWrapper;
+import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.NavHandle;
 import com.android.quickstep.RecentsAnimationDeviceState;
@@ -61,13 +62,14 @@
     private final NavHandle mNavHandle;
     private final StatsLogManager mStatsLogManager;
     private final TopTaskTracker mTopTaskTracker;
+    private final GestureState mGestureState;
 
     private MotionEvent mCurrentDownEvent;
     private boolean mDeepPressLogged;  // Whether deep press has been logged for the current touch.
 
     public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
             InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState,
-            NavHandle navHandle) {
+            NavHandle navHandle, GestureState gestureState) {
         super(delegate, inputMonitor);
         mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
         mDeepPressEnabled = DeviceConfigWrapper.get().getEnableLpnhDeepPress();
@@ -82,6 +84,8 @@
         mTouchSlopSquaredOriginal = deviceState.getSquaredTouchSlop();
         mTouchSlopSquared = mTouchSlopSquaredOriginal;
         mOuterTouchSlopSquared = mTouchSlopSquared * (twoStageMultiplier * twoStageMultiplier);
+        mGestureState = gestureState;
+        mGestureState.setIsInExtendedSlopRegion(false);
         if (DEBUG_NAV_HANDLE) {
             Log.d(TAG, "mLongPressTimeout=" + mLongPressTimeout);
             Log.d(TAG, "mOuterLongPressTimeout=" + mOuterLongPressTimeout);
@@ -126,6 +130,7 @@
                 }
                 mCurrentDownEvent = MotionEvent.obtain(ev);
                 mTouchSlopSquared = mTouchSlopSquaredOriginal;
+                mGestureState.setIsInExtendedSlopRegion(false);
                 mDeepPressLogged = false;
                 if (isInNavBarHorizontalArea(ev.getRawX())) {
                     mNavHandleLongPressHandler.onTouchStarted(mNavHandle);
@@ -154,6 +159,7 @@
                                 - (int) (ev.getEventTime() - ev.getDownTime());
                         MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress, delay);
                         mTouchSlopSquared = mOuterTouchSlopSquared;
+                        mGestureState.setIsInExtendedSlopRegion(true);
                         if (DEBUG_NAV_HANDLE) {
                             Log.d(TAG, "Touch in middle region!");
                         }
@@ -219,6 +225,7 @@
         if (DEBUG_NAV_HANDLE) {
             Log.d(TAG, "cancelLongPress");
         }
+        mGestureState.setIsInExtendedSlopRegion(false);
         MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
         mNavHandleLongPressHandler.onTouchFinished(mNavHandle, reason);
     }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 9f39476..0d450c6 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -284,8 +284,9 @@
 
                 float horizontalDist = Math.abs(displacementX);
                 float upDist = -displacement;
-                boolean passedSlop = mGestureState.isTrackpadGesture() || squaredHypot(
-                        displacementX, displacementY) >= mSquaredTouchSlop;
+                boolean passedSlop = mGestureState.isTrackpadGesture()
+                        || (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop
+                            && !mGestureState.isInExtendedSlopRegion());
 
                 if (!mPassedSlopOnThisGesture && passedSlop) {
                     mPassedSlopOnThisGesture = true;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index bb8d1d7..c61f71d 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -48,6 +48,7 @@
     private final BaseContainerInterface<?, T> mContainerInterface;
     private final BaseDragLayer mTarget;
     private final InputMonitorCompat mInputMonitor;
+    private final GestureState mGestureState;
 
     private final int[] mLocationOnScreen = new int[2];
 
@@ -62,6 +63,7 @@
         mInputMonitor = inputMonitor;
         mStartingInActivityBounds = startingInActivityBounds;
         mContainerInterface = gestureState.getContainerInterface();
+        mGestureState = gestureState;
 
         mTarget = container.getDragLayer();
         mTarget.getLocationOnScreen(mLocationOnScreen);
@@ -84,7 +86,10 @@
             ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
         }
         ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
-        boolean handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
+        boolean handled = false;
+        if (mGestureState == null || !mGestureState.isInExtendedSlopRegion()) {
+            handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
+        }
         ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
         ev.setEdgeFlags(flags);
 
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index cd180ba..9a25c32 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -28,6 +28,8 @@
 import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -42,6 +44,7 @@
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.touch.OverScroll;
 import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.systemui.shared.system.InputMonitorCompat;
@@ -51,6 +54,9 @@
  */
 public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
 
+    private static final int HOVER_TASKBAR_UNSTASH_TIMEOUT = 500;
+    private static final Handler sUnstashHandler = new Handler(Looper.getMainLooper());
+
     private final TaskbarActivityContext mTaskbarActivityContext;
     private final OverviewCommandHelper mOverviewCommandHelper;
     private final float mUnstashArea;
@@ -76,10 +82,11 @@
     private final int mStashedTaskbarBottomEdge;
 
     private final @Nullable TransitionCallback mTransitionCallback;
+    private final GestureState mGestureState;
 
     public TaskbarUnstashInputConsumer(Context context, InputConsumer delegate,
             InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext,
-            OverviewCommandHelper overviewCommandHelper) {
+            OverviewCommandHelper overviewCommandHelper, GestureState gestureState) {
         super(delegate, inputMonitor);
         mTaskbarActivityContext = taskbarActivityContext;
         mOverviewCommandHelper = overviewCommandHelper;
@@ -103,6 +110,7 @@
         mTransitionCallback = mIsTransientTaskbar
                 ? taskbarActivityContext.getTranslationCallbacks()
                 : null;
+        mGestureState = gestureState;
     }
 
     @Override
@@ -111,6 +119,11 @@
     }
 
     @Override
+    public boolean allowInterceptByParent() {
+        return super.allowInterceptByParent() && !mHasPassedTaskbarNavThreshold;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent ev) {
         if (mState != STATE_ACTIVE) {
             boolean isStashedTaskbarHovered = isMouseEvent(ev)
@@ -173,7 +186,8 @@
                             boolean passedTaskbarNavThreshold = dY < 0
                                     && Math.abs(dY) >= mTaskbarNavThreshold;
 
-                            if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
+                            if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold
+                                    && !mGestureState.isInExtendedSlopRegion()) {
                                 mHasPassedTaskbarNavThreshold = true;
                                 if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) {
                                     mTaskbarActivityContext.onSwipeToOpenBubblebar();
@@ -299,16 +313,25 @@
                 dp.heightPx);
 
         if (mBottomEdgeBounds.contains(x, y)) {
-            // If hovering stashed taskbar and then hover screen bottom edge, unstash it.
-            mTaskbarActivityContext.onSwipeToUnstashTaskbar();
-            mIsStashedTaskbarHovered = false;
+            // start a single unstash timeout if hovering bottom edge under the hinted taskbar.
+            if (!sUnstashHandler.hasMessagesOrCallbacks()) {
+                sUnstashHandler.postDelayed(() -> {
+                    mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+                    mIsStashedTaskbarHovered = false;
+                }, HOVER_TASKBAR_UNSTASH_TIMEOUT);
+            }
         } else if (!isStashedTaskbarHovered(x, y)) {
-            // If exit hovering stashed taskbar, remove hint.
+            // If exit hovering stashed taskbar, remove hint and clear pending unstash calls.
+            sUnstashHandler.removeCallbacksAndMessages(null);
             startStashedTaskbarHover(/* isHovered = */ false);
+        } else {
+            sUnstashHandler.removeCallbacksAndMessages(null);
         }
     }
 
     private void updateUnhoveredTaskbarState(int x, int y) {
+        sUnstashHandler.removeCallbacksAndMessages(null);
+
         DeviceProfile dp = mTaskbarActivityContext.getDeviceProfile();
         mBottomEdgeBounds.set(
                 0,
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index d5cc447..ad13efb 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -382,7 +382,7 @@
                 }
 
                 @Override
-                public void update(RectF rect, float progress, float radius) {
+                public void update(RectF rect, float progress, float radius, int overlayAlpha) {
                     mFakeIconView.setVisibility(View.VISIBLE);
                     mFakeIconView.update(rect, progress,
                             1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a09e027..3cae4dc 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -58,10 +58,6 @@
 import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LogConfig;
@@ -347,7 +343,6 @@
                         event.getId() + "";
                 Log.d(TAG, name);
             }
-            LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
 
             if (mSlice == null && mSliceItem != null) {
                 mSlice = LauncherAtom.Slice.newBuilder().setUri(
@@ -369,25 +364,17 @@
                 return;
             }
 
-            if (mItemInfo.container < 0 || appState == null) {
+            if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
+                // Item is inside a collection, fetch collection info in a BG thread
+                // and then write to StatsLog.
+                app.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->
+                        write(event, applyOverwrites(mItemInfo.buildProto(
+                                dataModel.collections.get(mItemInfo.container)))));
+            })) {
                 // Write log on the model thread so that logs do not go out of order
                 // (for eg: drop comes after drag)
                 Executors.MODEL_EXECUTOR.execute(
                         () -> write(event, applyOverwrites(mItemInfo.buildProto())));
-            } else {
-                // Item is inside a collection, fetch collection info in a BG thread
-                // and then write to StatsLog.
-                appState.getModel().enqueueModelUpdateTask(
-                        new BaseModelUpdateTask() {
-                            @Override
-                            public void execute(@NonNull final LauncherAppState app,
-                                    @NonNull final BgDataModel dataModel,
-                                    @NonNull final AllAppsList apps) {
-                                CollectionInfo collectionInfo =
-                                        dataModel.collections.get(mItemInfo.container);
-                                write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
-                            }
-                        });
             }
         }
 
@@ -405,6 +392,20 @@
                 case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
                     InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
                     break;
+                case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN:
+                    InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+                    break;
+                case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END:
+                    InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+                    break;
+                case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN:
+                    InteractionJankMonitorWrapper.begin(
+                            view,
+                            Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+                    break;
+                case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END:
+                    InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+                    break;
                 default:
                     break;
             }
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt
new file mode 100644
index 0000000..28212cf
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.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.quickstep.recents.viewmodel
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+// This is far from complete but serves the purpose of enabling refactoring in other areas
+class RecentsViewData {
+    val fullscreenProgress = MutableStateFlow(1f)
+
+    // This is typically a View concern but it is used to invalidate rendering in other Views
+    val scale = MutableStateFlow(1f)
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
new file mode 100644
index 0000000..0843ae3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.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.quickstep.task.thumbnail
+
+import com.android.systemui.shared.recents.model.Task
+
+sealed class TaskThumbnailUiState {
+    data object Uninitialized : TaskThumbnailUiState()
+    data object LiveTile : TaskThumbnailUiState()
+}
+
+data class TaskThumbnail(val task: Task, val isRunning: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
new file mode 100644
index 0000000..b466f3f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Canvas
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import com.android.launcher3.Utilities
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
+import com.android.quickstep.util.TaskCornerRadius
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.system.QuickStepContract
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.launch
+
+class TaskThumbnailView : View {
+    // TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
+    //  to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
+    //  This is using a lazy for now because the dependencies cannot be obtained without DI.
+    val viewModel by lazy {
+        TaskThumbnailViewModel(
+            RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+                .getOverviewPanel<RecentsView<*, *>>()
+                .mRecentsViewData,
+            (parent as TaskView).mTaskViewData
+        )
+    }
+
+    private var uiState: TaskThumbnailUiState = Uninitialized
+    private var inheritedScale: Float = 1f
+
+    private var cornerRadius: Float = TaskCornerRadius.get(context)
+    private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
+
+    constructor(context: Context?) : super(context)
+    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+    constructor(
+        context: Context?,
+        attrs: AttributeSet?,
+        defStyleAttr: Int,
+    ) : super(context, attrs, defStyleAttr)
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        // TODO(b/335396935) replace MainScope with shorter lifecycle.
+        MainScope().launch {
+            viewModel.uiState.collect { viewModelUiState ->
+                uiState = viewModelUiState
+                invalidate()
+            }
+        }
+        MainScope().launch { viewModel.recentsFullscreenProgress.collect { invalidateOutline() } }
+        MainScope().launch {
+            viewModel.inheritedScale.collect { viewModelInheritedScale ->
+                inheritedScale = viewModelInheritedScale
+                invalidateOutline()
+            }
+        }
+
+        clipToOutline = true
+        outlineProvider =
+            object : ViewOutlineProvider() {
+                override fun getOutline(view: View, outline: Outline) {
+                    outline.setRoundRect(
+                        0,
+                        0,
+                        view.measuredWidth,
+                        view.measuredHeight,
+                        getCurrentCornerRadius()
+                    )
+                }
+            }
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        when (uiState) {
+            is Uninitialized -> {}
+            is LiveTile -> drawTransparentUiState(canvas)
+        }
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration?) {
+        super.onConfigurationChanged(newConfig)
+
+        cornerRadius = TaskCornerRadius.get(context)
+        fullscreenCornerRadius = QuickStepContract.getWindowCornerRadius(context)
+        invalidateOutline()
+    }
+
+    private fun drawTransparentUiState(canvas: Canvas) {
+        canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+    }
+
+    private fun getCurrentCornerRadius() =
+        Utilities.mapRange(
+            viewModel.recentsFullscreenProgress.value,
+            cornerRadius,
+            fullscreenCornerRadius
+        ) / inheritedScale
+
+    companion object {
+        private val CLEAR_PAINT =
+            Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
new file mode 100644
index 0000000..71bc865
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
+import com.android.quickstep.task.viewmodel.TaskViewData
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
+    private val task = MutableStateFlow<TaskThumbnail?>(null)
+
+    val recentsFullscreenProgress = recentsViewData.fullscreenProgress
+    val inheritedScale =
+        combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
+            recentsScale * taskScale
+        }
+    val uiState =
+        task.map { taskVal ->
+            when {
+                taskVal == null -> Uninitialized
+                taskVal.isRunning -> LiveTile
+                else -> Uninitialized
+            }
+        }
+
+    fun bind(task: TaskThumbnail) {
+        this.task.value = task
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
new file mode 100644
index 0000000..a8b5112
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.viewmodel
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class TaskViewData {
+    // This is typically a View concern but it is used to invalidate rendering in other Views
+    val scale = MutableStateFlow(1f)
+}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index e3772bd..cfa6b98 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -277,7 +277,8 @@
                     errorDetected |= printErrorIfTrue(
                             true,
                             prefix,
-                            /* errorMessage= */ "new gesture attempted while a requested recents"
+                            /* errorMessage= */ (eventEntry.getDuplicateCount() + 1)
+                                    + " gesture(s) attempted while a requested recents"
                                     + " animation is still pending.",
                             writer);
                     break;
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 1e05a69..c54862a 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -216,6 +216,10 @@
             return gestureEvent;
         }
 
+        public int getDuplicateCount() {
+            return duplicateCount;
+        }
+
         private void update(
                 @NonNull CompoundString compoundString,
                 ActiveGestureErrorDetector.GestureEvent gestureEvent) {
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 3f06571..e4e2eb2 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -22,6 +22,7 @@
 import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_LAUNCH;
 import static com.android.launcher3.model.data.AppInfo.PACKAGE_KEY_COMPARATOR;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SUPPORTS_MULTI_INSTANCE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -32,34 +33,38 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.jank.Cuj;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.apppairs.AppPairIcon;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
 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.taskbar.TaskbarActivityContext;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.TaskView;
@@ -101,6 +106,55 @@
     }
 
     /**
+     * Returns whether the specified GroupedTaskView can be saved as an app pair.
+     */
+    public boolean canSaveAppPair(TaskView taskView) {
+        if (mContext == null) {
+            // Can ignore as the activity is already destroyed
+            return false;
+        }
+
+        // Disallow saving app pairs if:
+        // - app pairs feature is not enabled
+        // - the task in question is a single task
+        // - at least one app in app pair is unpinnable
+        // - the task is not a GroupedTaskView
+        // - both tasks in the GroupedTaskView are from the same app and the app does not
+        //   support multi-instance
+        boolean hasUnpinnableApp = taskView.getTaskContainers().stream()
+                .anyMatch(att -> att != null && att.getItemInfo() != null
+                        && ((att.getItemInfo().runtimeStatusFlags
+                            & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
+        if (!FeatureFlags.enableAppPairs()
+                || !taskView.containsMultipleTasks()
+                || hasUnpinnableApp
+                || !(taskView instanceof GroupedTaskView)) {
+            return false;
+        }
+
+        GroupedTaskView gtv = (GroupedTaskView) taskView;
+        List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+        ComponentKey taskKey1 = TaskUtils.getLaunchComponentKeyForTask(
+                containers.get(0).getTask().key);
+        ComponentKey taskKey2 = TaskUtils.getLaunchComponentKeyForTask(
+                containers.get(1).getTask().key);
+        AppInfo app1 = resolveAppInfoByComponent(taskKey1);
+        AppInfo app2 = resolveAppInfoByComponent(taskKey2);
+
+        if (app1 == null || app2 == null) {
+            // Disallow saving app pairs for apps that don't have a front-door in Launcher
+            return false;
+        }
+
+        if (PackageManagerHelper.isSameAppForMultiInstance(app1, app2)) {
+            if (!app1.supportsMultiInstance() || !app2.supportsMultiInstance()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Creates a new app pair ItemInfo and adds it to the workspace.
      * <br>
      * We create WorkspaceItemInfos to save onto the app pair in the following way:
@@ -116,34 +170,26 @@
      */
     public void saveAppPair(GroupedTaskView gtv) {
         InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
-        TaskView.TaskIdAttributeContainer[] attributes = gtv.getTaskIdAttributeContainers();
-        WorkspaceItemInfo recentsInfo1 = attributes[0].getItemInfo();
-        WorkspaceItemInfo recentsInfo2 = attributes[1].getItemInfo();
-        WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
-        WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
+        List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+        WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo();
+        WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo();
+        WorkspaceItemInfo app1 = resolveAppPairWorkspaceInfo(recentsInfo1);
+        WorkspaceItemInfo app2 = resolveAppPairWorkspaceInfo(recentsInfo2);
 
-        // If app lookup fails, use the WorkspaceItemInfo that we have, but try to override default
-        // intent with one from PackageManager.
-        if (app1 == null) {
-            Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo1.title
-                    + " failed. Falling back to the WorkspaceItemInfo from Recents.");
-            app1 = convertRecentsItemToAppItem(recentsInfo1);
+        if (app1 == null || app2 == null) {
+            // This shouldn't happen if canSaveAppPair() is called above, but log an error and do
+            // not create the app pair if the workspace items can't be resolved
+            Log.w(TAG, "Failed to save app pair due to invalid apps ("
+                    + "app1=" + recentsInfo1.getComponentKey().componentName
+                    + " app2=" + recentsInfo2.getComponentKey().componentName + ")");
+            return;
         }
-        if (app2 == null) {
-            Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo2.title
-                    + " failed. Falling back to the WorkspaceItemInfo from Recents.");
-            app2 = convertRecentsItemToAppItem(recentsInfo2);
-        }
-
-        // WorkspaceItemProcessor won't process these new ItemInfos until the next launcher restart,
-        // so update some flags now.
-        updateWorkspaceItemFlags(app1);
-        updateWorkspaceItemFlags(app2);
 
         @PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
         if (!isPersistentSnapPosition(snapPosition)) {
-            // if we received an illegal snap position, log an error and do not create the app pair.
-            Log.wtf(TAG, "tried to save an app pair with illegal snapPosition " + snapPosition);
+            // If we received an illegal snap position, log an error and do not create the app pair
+            Log.wtf(TAG, "Tried to save an app pair with illegal snapPosition "
+                    + snapPosition);
             return;
         }
 
@@ -229,69 +275,38 @@
     }
 
     /**
+     * Returns an AppInfo associated with the app for the given ComponentKey, or null if no such
+     * package exists in the AllAppsStore.
+     */
+    @Nullable
+    private AppInfo resolveAppInfoByComponent(@NonNull ComponentKey key) {
+        AllAppsStore appsStore = ActivityContext.lookupContext(mContext)
+                .getAppsView().getAppsStore();
+
+        // First look up the app info in order of:
+        // - The exact activity for the recent task
+        // - The first(?) loaded activity from the package
+        AppInfo appInfo = appsStore.getApp(key);
+        if (appInfo == null) {
+            appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR);
+        }
+        return appInfo;
+    }
+
+    /**
      * Creates a new launchable WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION by looking the
      * ComponentKey up in the AllAppsStore. If no app is found, attempts a lookup by package
      * instead. If that lookup fails, returns null.
      */
     @Nullable
-    private WorkspaceItemInfo lookupLaunchableItem(@Nullable ComponentKey key) {
-        if (key == null) {
+    private WorkspaceItemInfo resolveAppPairWorkspaceInfo(
+            @NonNull WorkspaceItemInfo recentTaskInfo) {
+        // ComponentKey should never be null (see TaskView#getItemInfo)
+        AppInfo appInfo = resolveAppInfoByComponent(recentTaskInfo.getComponentKey());
+        if (appInfo == null) {
             return null;
         }
-
-        AllAppsStore appsStore = ActivityContext.lookupContext(mContext)
-                .getAppsView().getAppsStore();
-
-        // Lookup by ComponentKey
-        AppInfo appInfo = appsStore.getApp(key);
-        if (appInfo == null) {
-            // Lookup by package
-            appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR);
-        }
-
-        return appInfo != null ? appInfo.makeWorkspaceItem(mContext) : null;
-    }
-
-    /**
-     * Updates flags for newly created WorkspaceItemInfos.
-     */
-    private void updateWorkspaceItemFlags(WorkspaceItemInfo wii) {
-        PackageManager pm = mContext.getPackageManager();
-        ActivityInfo ai = null;
-        try {
-            ai = pm.getActivityInfo(wii.getTargetComponent(), 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "PackageManager lookup failed.");
-        }
-
-        if (ai != null) {
-            wii.status = ai.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
-                    ? wii.status | WorkspaceItemInfo.FLAG_NON_RESIZEABLE
-                    : wii.status & ~WorkspaceItemInfo.FLAG_NON_RESIZEABLE;
-        }
-    }
-
-    /**
-     * Converts a WorkspaceItemInfo of itemType=ITEM_TYPE_TASK (from a Recents task) to a new
-     * WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION.
-     */
-    private WorkspaceItemInfo convertRecentsItemToAppItem(WorkspaceItemInfo recentsItem) {
-        if (recentsItem.itemType != LauncherSettings.Favorites.ITEM_TYPE_TASK) {
-            Log.w(TAG, "Expected ItemInfo of type ITEM_TYPE_TASK, but received "
-                    + recentsItem.itemType);
-        }
-
-        WorkspaceItemInfo launchableItem = recentsItem.clone();
-        PackageManager p = mContext.getPackageManager();
-        Intent launchIntent = p.getLaunchIntentForPackage(recentsItem.getTargetPackage());
-        Log.w(TAG, "Initial intent from Recents: " + launchableItem.intent + "\n"
-                + "Intent from PackageManager: " + launchIntent);
-        if (launchIntent != null) {
-            // If lookup from PackageManager fails, just use the existing intent
-            launchableItem.intent = launchIntent;
-        }
-        launchableItem.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-        return launchableItem;
+        return appInfo.makeWorkspaceItem(mContext);
     }
 
     /**
@@ -318,7 +333,7 @@
                 itemInfos.stream().map(ItemInfo::getComponentKey).toList();
 
         // Use TopTaskTracker to find the currently running app (or apps)
-        TopTaskTracker topTaskTracker = getTopTaskTracker(context);
+        TopTaskTracker topTaskTracker = getTopTaskTracker();
 
         // getRunningSplitTasksIds() will return a pair of ids if we are currently running a
         // split pair, or an empty array with zero length if we are running a single app.
@@ -491,7 +506,7 @@
      * Gets the TopTaskTracker, which is a cached record of the top running Task.
      */
     @VisibleForTesting
-    public TopTaskTracker getTopTaskTracker(Context context) {
-        return TopTaskTracker.INSTANCE.get(context);
+    public TopTaskTracker getTopTaskTracker() {
+        return TopTaskTracker.INSTANCE.get(mContext);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index a3904bc..7acb28d 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -20,36 +20,32 @@
 import com.android.launcher3.R;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.io.PrintWriter;
 import java.util.Optional;
 
 /** Class to manage Assistant states. */
-public class AssistStateManager implements ResourceBasedOverride {
+public class AssistStateManager implements ResourceBasedOverride, SafeCloseable {
 
     public static final MainThreadInitializedObject<AssistStateManager> INSTANCE =
             forOverride(AssistStateManager.class, R.string.assist_state_manager_class);
 
     public AssistStateManager() {}
 
-    /** Whether search supports haptic on invocation. */
-    public boolean supportsCommitHaptic() {
+    /** Return {@code true} if the Settings toggle is enabled. */
+    public boolean isSettingsAllEntrypointsEnabled() {
         return false;
     }
 
-    /** Whether search is available. */
-    public boolean isSearchAvailable() {
+    /** Whether search supports showing on the lockscreen. */
+    public boolean supportsShowWhenLocked() {
         return false;
     }
 
-    /** Whether CsHelper CtS invocation path is available. */
-    public Optional<Boolean> isCsHelperAvailable() {
-        return Optional.empty();
-    }
-
-    /** Whether VIS CtS invocation path is available. */
-    public Optional<Boolean> isVisAvailable() {
-        return Optional.empty();
+    /** Whether ContextualSearchService invocation path is available. */
+    public boolean isContextualSearchServiceAvailable() {
+        return false;
     }
 
     /** Get the Launcher overridden long press nav handle duration to trigger Assistant. */
@@ -84,11 +80,14 @@
         return 0;
     }
 
-    /** Return {@code true} if the Settings toggle is enabled. */
-    public boolean isSettingsAllEntrypointsEnabled() {
-        return false;
+    /** Get the haptic bit overridden by AGSA. */
+    public Optional<Boolean> getShouldPlayHapticOverride() {
+        return Optional.empty();
     }
 
     /** Dump states. */
     public void dump(String prefix, PrintWriter writer) {}
+
+    @Override
+    public void close() {}
 }
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index b3f5d82..07f2d68 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -56,4 +56,10 @@
     public DesktopTask copy() {
         return new DesktopTask(tasks);
     }
+
+    @Override
+    public String toString() {
+        return "type=" + taskViewType + " tasks=" + tasks;
+    }
+
 }
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
index 544c64d..d36dc7e 100644
--- a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -48,12 +48,14 @@
                 PropReader(
                     object : PropProvider {
                         override fun <T : Any> get(key: String, fallback: T): T {
-                            if (fallback is Int)
+                            if (fallback is Int) {
+                                allKeys.add(key)
                                 return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
-                            else if (fallback is Boolean)
+                            } else if (fallback is Boolean) {
+                                allKeys.add(key)
                                 return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
                                     as T
-                            else return fallback
+                            } else return fallback
                         }
                     }
                 )
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index 9c49647..7dd6afc 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -70,4 +70,10 @@
                 task2 != null ? new Task(task2) : null,
                 mSplitBounds);
     }
+
+    @Override
+    public String toString() {
+        return "type=" + taskViewType + " task1=" + task1 + " task2=" + task2;
+    }
+
 }
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 9df568e..2a27dea 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -136,21 +136,16 @@
             });
         }
 
-        if (!ALL_APPS_VISITED_COUNT.hasReachedMax(launcher)) {
+        if (!Utilities.isRunningInTestHarness()) {
             launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
                 @Override
                 public void onStateTransitionComplete(LauncherState finalState) {
                     if (finalState == ALL_APPS) {
                         ALL_APPS_VISITED_COUNT.increment(launcher);
-                        return;
                     }
-
-                    boolean hasReachedMaxCount = ALL_APPS_VISITED_COUNT.hasReachedMax(launcher);
-                    launcher.getAppsView().getFloatingHeaderView().findFixedRowByType(
-                            AppsDividerView.class).setShowAllAppsLabel(!hasReachedMaxCount);
-                    if (hasReachedMaxCount) {
-                        launcher.getStateManager().removeStateListener(this);
-                    }
+                    launcher.getAppsView().getFloatingHeaderView()
+                            .findFixedRowByType(AppsDividerView.class)
+                            .setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(launcher));
                 }
             });
         }
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index c39056d..5505bb3 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -171,8 +171,13 @@
 
     public void onTargetPositionChanged() {
         if (enableScalingRevealHomeAnimation()) {
+            if (isEnded()) {
+                return;
+            }
+
             if (mRectXSpring != null) {
                 mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
+                mRectXAnimEnded = false;
             }
 
             if (mRectYSpring != null) {
@@ -187,6 +192,7 @@
                         mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
                         break;
                 }
+                mRectYAnimEnded = false;
             }
         } else {
             if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
@@ -297,6 +303,7 @@
                                             .setStiffness(stiffnessZ)
                                             .setDampingRatio(dampingZ))
                             .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+                            .setMaxValue(1f)
                             .setMinimumVisibleChange(minVisibleChange)
                             .addEndListener((animation, canceled, value, velocity) -> {
                                 mRectScaleAnimEnded = true;
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index 48c2407..1bf77f1 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -16,7 +16,10 @@
 
 package com.android.quickstep.util
 
+import android.graphics.Matrix
+import android.graphics.RectF
 import android.view.View
+import androidx.core.graphics.transform
 import com.android.app.animation.Interpolators
 import com.android.app.animation.Interpolators.EMPHASIZED
 import com.android.app.animation.Interpolators.LINEAR
@@ -38,7 +41,11 @@
  * Creates an animation where the workspace and hotseat fade in while revealing from the center of
  * the screen outwards radially. This is used in conjunction with the swipe up to home animation.
  */
-class ScalingWorkspaceRevealAnim(launcher: QuickstepLauncher) {
+class ScalingWorkspaceRevealAnim(
+    launcher: QuickstepLauncher,
+    siblingAnimation: RectFSpringAnim?,
+    windowTargetRect: RectF?
+) {
     companion object {
         private const val FADE_DURATION_MS = 200L
         private const val SCALE_DURATION_MS = 1000L
@@ -52,11 +59,11 @@
 
     init {
         // Make sure the starting state is right for the animation.
-        val config = StateAnimationConfig()
-        config.animFlags = SKIP_OVERVIEW.or(SKIP_DEPTH_CONTROLLER).or(SKIP_SCRIM)
-        config.duration = 0
+        val setupConfig = StateAnimationConfig()
+        setupConfig.animFlags = SKIP_OVERVIEW.or(SKIP_DEPTH_CONTROLLER).or(SKIP_SCRIM)
+        setupConfig.duration = 0
         launcher.stateManager
-            .createAtomicAnimation(LauncherState.BACKGROUND_APP, LauncherState.NORMAL, config)
+            .createAtomicAnimation(LauncherState.BACKGROUND_APP, LauncherState.NORMAL, setupConfig)
             .start()
         launcher
             .getOverviewPanel<RecentsView<QuickstepLauncher, LauncherState>>()
@@ -64,7 +71,7 @@
         launcher.workspace.stateTransitionAnimation.setScrim(
             PropertySetter.NO_ANIM_PROPERTY_SETTER,
             LauncherState.BACKGROUND_APP,
-            config
+            setupConfig
         )
 
         val workspace = launcher.workspace
@@ -103,11 +110,55 @@
             Interpolators.clampToProgress(LINEAR, 0f, fadeClamp)
         )
 
+        val transitionConfig = StateAnimationConfig()
+
         // Match the Wallpaper animation to the rest of the content.
         val depthController = (launcher as? QuickstepLauncher)?.depthController
-        val depthConfig = StateAnimationConfig()
-        depthConfig.setInterpolator(StateAnimationConfig.ANIM_DEPTH, EMPHASIZED)
-        depthController?.setStateWithAnimation(LauncherState.NORMAL, depthConfig, animation)
+        transitionConfig.setInterpolator(StateAnimationConfig.ANIM_DEPTH, EMPHASIZED)
+        depthController?.setStateWithAnimation(LauncherState.NORMAL, transitionConfig, animation)
+
+        // Make sure that the contrast scrim animates correctly if needed.
+        transitionConfig.setInterpolator(StateAnimationConfig.ANIM_SCRIM_FADE, EMPHASIZED)
+        launcher.workspace.stateTransitionAnimation.setScrim(
+            animation,
+            LauncherState.NORMAL,
+            transitionConfig
+        )
+
+        // To avoid awkward jumps in icon position, we want the sibling animation to always be
+        // targeting the current position. Since we can't easily access this, instead we calculate
+        // it using the animation of the whole of home.
+        // We start by caching the final target position, as this is the base for the transforms.
+        val originalTarget = RectF(windowTargetRect)
+        animation.addOnFrameListener {
+            val transformed = RectF(originalTarget)
+
+            // First we scale down using the same pivot as the workspace scale, so we find the
+            // correct position AND size.
+            transformed.transform(
+                Matrix().apply {
+                    setScale(workspace.scaleX, workspace.scaleY, workspace.pivotX, workspace.pivotY)
+                }
+            )
+            // Then we scale back up around the center of the current position. This is because the
+            // icon animation behaves poorly if it is given a target that is smaller than the size
+            // of the icon.
+            transformed.transform(
+                Matrix().apply {
+                    setScale(
+                        1 / workspace.scaleX,
+                        1 / workspace.scaleY,
+                        transformed.centerX(),
+                        transformed.centerY()
+                    )
+                }
+            )
+
+            if (transformed != windowTargetRect) {
+                windowTargetRect?.set(transformed)
+                siblingAnimation?.onTargetPositionChanged()
+            }
+        }
 
         // Needed to avoid text artefacts during the scale animation.
         workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 021c455..40ea70f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -23,6 +23,7 @@
 import android.animation.ObjectAnimator
 import android.animation.ValueAnimator
 import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
 import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
 import android.content.Context
 import android.graphics.Bitmap
@@ -50,6 +51,7 @@
 import com.android.launcher3.apppairs.AppPairIcon
 import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.logging.StatsLogManager.EventEnum
+import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.statehandlers.DepthController
 import com.android.launcher3.statemanager.StateManager
 import com.android.launcher3.taskbar.TaskbarActivityContext
@@ -65,10 +67,11 @@
 import com.android.quickstep.views.RecentsView
 import com.android.quickstep.views.RecentsViewContainer
 import com.android.quickstep.views.SplitInstructionsView
-import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskThumbnailViewDeprecated
 import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
 import com.android.quickstep.views.TaskViewIcon
+import com.android.wm.shell.shared.TransitionUtil
 import java.util.Optional
 import java.util.function.Supplier
 
@@ -111,7 +114,7 @@
         } else if (splitSelectStateController.isDismissingFromSplitPair) {
             // Initiating split from overview, but on a split pair
             val taskView = taskViewSupplier.get()
-            for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
+            for (container: TaskContainer in taskView.taskContainers) {
                 if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
                     val drawable = getDrawable(container.iconView, splitSelectSource)
                     return SplitAnimInitProps(
@@ -131,15 +134,17 @@
         } else {
             // Initiating split from overview on fullscreen task TaskView
             val taskView = taskViewSupplier.get()
-            val drawable = getDrawable(taskView.iconView, splitSelectSource)
-            return SplitAnimInitProps(
-                taskView.thumbnail,
-                taskView.thumbnail.thumbnail,
-                drawable!!,
-                fadeWithThumbnail = true,
-                isStagedTask = true,
-                taskView.iconView.asView()
-            )
+            taskView.taskContainers.first().let {
+                val drawable = getDrawable(it.iconView, splitSelectSource)
+                return SplitAnimInitProps(
+                    it.thumbnailView,
+                    it.thumbnailView.thumbnail,
+                    drawable!!,
+                    fadeWithThumbnail = true,
+                    isStagedTask = true,
+                    iconView = it.iconView.asView()
+                )
+            }
         }
     }
 
@@ -160,9 +165,9 @@
     /**
      * When selecting first app from split pair, second app's thumbnail remains. This animates the
      * second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
-     * with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app
-     * that **was not** selected as the first split app should be the container that's passed
-     * through.
+     * with [TaskThumbnailViewDeprecated]'s splashView. Adds animations to the provided builder.
+     * Note: The app that **was not** selected as the first split app should be the container that's
+     * passed through.
      *
      * @param builder Adds animation to this
      * @param taskIdAttributeContainer container of the app that **was not** selected
@@ -170,7 +175,7 @@
      *   (opposite of that representing [taskIdAttributeContainer])
      */
     fun addInitialSplitFromPair(
-        taskIdAttributeContainer: TaskIdAttributeContainer,
+        taskIdAttributeContainer: TaskContainer,
         builder: PendingAnimation,
         deviceProfile: DeviceProfile,
         taskViewWidth: Int,
@@ -179,7 +184,7 @@
     ) {
         val thumbnail = taskIdAttributeContainer.thumbnailView
         val iconView: View = taskIdAttributeContainer.iconView.asView()
-        builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
+        builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailViewDeprecated.SPLASH_ALPHA, 1f))
         thumbnail.setShowSplashForSplitSelection(true)
         // With the new `IconAppChipView`, we always want to keep the chip pinned to the
         // top left of the task / thumbnail.
@@ -202,7 +207,7 @@
             builder.add(
                 ObjectAnimator.ofFloat(
                     thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
+                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
                     centerThumbnailTranslationX
                 )
             )
@@ -224,7 +229,7 @@
             builder.add(
                 ObjectAnimator.ofFloat(
                     thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
                     translateYResetVal
                 )
             )
@@ -252,7 +257,7 @@
             builder.add(
                 ObjectAnimator.ofFloat(
                     thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
                     centerThumbnailTranslationY
                 )
             )
@@ -266,7 +271,11 @@
             // Reset other dimensions
             thumbnail.scaleX = 1f
             builder.add(
-                ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)
+                ObjectAnimator.ofFloat(
+                    thumbnail,
+                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
+                    0f
+                )
             )
         }
     }
@@ -276,43 +285,59 @@
      * [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
      *
      * [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
-     * screen, not the logical second app.
-     * For landscape it's the left app and for portrait the top one.
+     * screen, not the logical second app. For landscape it's the left app and for portrait the top
+     * one.
      */
-    fun addDividerPlaceholderViewToAnim(pendingAnimation: PendingAnimation,
-                                        container: RecentsViewContainer,
-                                        secondPlaceholderEndingBounds: Rect,
-                                        context: Context) : View {
+    fun addDividerPlaceholderViewToAnim(
+        pendingAnimation: PendingAnimation,
+        container: RecentsViewContainer,
+        secondPlaceholderEndingBounds: Rect,
+        context: Context
+    ): View {
         val mSplitDividerPlaceholderView = View(context)
         val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
-        val dp : com.android.launcher3.DeviceProfile = container.getDeviceProfile()
+        val dp: com.android.launcher3.DeviceProfile = container.getDeviceProfile()
         // Add it before/under the most recently added first floating taskView
-        val firstAddedSplitViewIndex: Int = container.getDragLayer().indexOfChild(
-                recentsView.splitSelectController.firstFloatingTaskView)
+        val firstAddedSplitViewIndex: Int =
+            container
+                .getDragLayer()
+                .indexOfChild(recentsView.splitSelectController.firstFloatingTaskView)
         container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
         val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
         lp.topMargin = 0
 
         if (dp.isLeftRightSplit) {
             lp.height = secondPlaceholderEndingBounds.height()
-            lp.width = container.asContext().resources.
-                getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
-            mSplitDividerPlaceholderView.translationX = secondPlaceholderEndingBounds.right - lp.width / 2f
+            lp.width =
+                container
+                    .asContext()
+                    .resources
+                    .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+            mSplitDividerPlaceholderView.translationX =
+                secondPlaceholderEndingBounds.right - lp.width / 2f
             mSplitDividerPlaceholderView.translationY = 0f
         } else {
-            lp.height = container.asContext().resources
+            lp.height =
+                container
+                    .asContext()
+                    .resources
                     .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
             lp.width = secondPlaceholderEndingBounds.width()
-            mSplitDividerPlaceholderView.translationY = secondPlaceholderEndingBounds.top - lp.height / 2f
+            mSplitDividerPlaceholderView.translationY =
+                secondPlaceholderEndingBounds.top - lp.height / 2f
             mSplitDividerPlaceholderView.translationX = 0f
         }
 
         mSplitDividerPlaceholderView.alpha = 0f
-        mSplitDividerPlaceholderView.setBackgroundColor(container.asContext().resources
-                .getColor(R.color.taskbar_background_dark))
+        mSplitDividerPlaceholderView.setBackgroundColor(
+            container.asContext().resources.getColor(R.color.taskbar_background_dark)
+        )
         val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
-        pendingAnimation.setViewAlpha(mSplitDividerPlaceholderView, 1f,
-                Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f))
+        pendingAnimation.setViewAlpha(
+            mSplitDividerPlaceholderView,
+            1f,
+            Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f)
+        )
         return mSplitDividerPlaceholderView
     }
 
@@ -533,8 +558,19 @@
             check(info != null && t != null) {
                 "trying to launch an app pair icon, but encountered an unexpected null"
             }
-
-            composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
+            val appPairLaunchingAppIndex = hasChangesForBothAppPairs(launchingIconView, info)
+            if (appPairLaunchingAppIndex == -1) {
+                // Launch split app pair animation
+                composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
+            } else {
+                composeFullscreenIconSplitLaunchAnimator(
+                    launchingIconView,
+                    info,
+                    t,
+                    finishCallback,
+                    appPairLaunchingAppIndex
+                )
+            }
         } else {
             // Fallback case: simple fade-in animation
             check(info != null && t != null) {
@@ -599,6 +635,43 @@
     }
 
     /**
+     * @return -1 if [transitionInfo] contains both apps of the app pair to be animated, otherwise
+     *   the integer index corresponding to [launchingIconView]'s contents for the single app to be
+     *   animated
+     */
+    fun hasChangesForBothAppPairs(
+        launchingIconView: AppPairIcon,
+        transitionInfo: TransitionInfo
+    ): Int {
+        val intent1 = launchingIconView.info.getFirstApp().intent.component?.packageName
+        val intent2 = launchingIconView.info.getSecondApp().intent.component?.packageName
+        var launchFullscreenAppIndex = -1
+        for (change in transitionInfo.changes) {
+            val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+            if (
+                TransitionUtil.isOpeningType(change.mode) &&
+                    taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN
+            ) {
+                val baseIntent = taskInfo.baseIntent.component?.packageName
+                if (baseIntent == intent1) {
+                    if (launchFullscreenAppIndex > -1) {
+                        launchFullscreenAppIndex = -1
+                        break
+                    }
+                    launchFullscreenAppIndex = 0
+                } else if (baseIntent == intent2) {
+                    if (launchFullscreenAppIndex > -1) {
+                        launchFullscreenAppIndex = -1
+                        break
+                    }
+                    launchFullscreenAppIndex = 1
+                }
+            }
+        }
+        return launchFullscreenAppIndex
+    }
+
+    /**
      * When the user taps an app pair icon to launch split, this will play the tasks' launch
      * animation from the position of the icon.
      *
@@ -633,7 +706,12 @@
         // If launching an app pair from Taskbar inside of an app context (no access to Launcher),
         // use the scale-up animation
         if (launchingIconView.context is TaskbarActivityContext) {
-            composeScaleUpLaunchAnimation(transitionInfo, t, finishCallback)
+            composeScaleUpLaunchAnimation(
+                transitionInfo,
+                t,
+                finishCallback,
+                WINDOWING_MODE_MULTI_WINDOW
+            )
             return
         }
 
@@ -643,11 +721,6 @@
 
         // Create an AnimatorSet that will run both shell and launcher transitions together
         val launchAnimation = AnimatorSet()
-        val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
-        val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
-        progressUpdater.setDuration(timings.getDuration().toLong())
-        progressUpdater.interpolator = Interpolators.LINEAR
-
         var rootCandidate: Change? = null
 
         for (change in transitionInfo.changes) {
@@ -691,6 +764,122 @@
         // Make sure nothing weird happened, like getChange() returning null.
         check(rootCandidate != null) { "Failed to find a root leash" }
 
+        // Create a new floating view in Launcher, positioned above the launching icon
+        val drawableArea = launchingIconView.iconDrawableArea
+        val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
+        val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
+        appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+        appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+
+        val floatingView =
+            FloatingAppPairView.getFloatingAppPairView(
+                launcher,
+                drawableArea,
+                appIcon1,
+                appIcon2,
+                dividerPos
+            )
+        floatingView.bringToFront()
+
+        launchAnimation.play(
+            getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+        )
+        launchAnimation.start()
+    }
+
+    /**
+     * Similar to [composeIconSplitLaunchAnimator], but instructs [FloatingAppPairView] to animate a
+     * single fullscreen icon + background instead of for a pair
+     */
+    @VisibleForTesting
+    fun composeFullscreenIconSplitLaunchAnimator(
+        launchingIconView: AppPairIcon,
+        transitionInfo: TransitionInfo,
+        t: Transaction,
+        finishCallback: Runnable,
+        launchFullscreenIndex: Int
+    ) {
+        // If launching an app pair from Taskbar inside of an app context (no access to Launcher),
+        // use the scale-up animation
+        if (launchingIconView.context is TaskbarActivityContext) {
+            composeScaleUpLaunchAnimation(
+                transitionInfo,
+                t,
+                finishCallback,
+                WINDOWING_MODE_FULLSCREEN
+            )
+            return
+        }
+
+        // Else we are in Launcher and can launch with the full icon stretch-and-split animation.
+        val launcher = QuickstepLauncher.getLauncher(launchingIconView.context)
+        val dp = launcher.deviceProfile
+
+        // Create an AnimatorSet that will run both shell and launcher transitions together
+        val launchAnimation = AnimatorSet()
+
+        val appInfo =
+            launchingIconView.info.getContents()[launchFullscreenIndex] as WorkspaceItemInfo
+        val intentToLaunch = appInfo.intent.component?.packageName
+        var rootCandidate: Change? = null
+        for (change in transitionInfo.changes) {
+            val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+            val baseIntent = taskInfo.baseIntent.component?.packageName
+            if (
+                TransitionUtil.isOpeningType(change.mode) &&
+                    taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN &&
+                    baseIntent == intentToLaunch
+            ) {
+                rootCandidate = change
+            }
+        }
+
+        // If we could not find a proper root candidate, something went wrong.
+        check(rootCandidate != null) { "Could not find a split root candidate" }
+
+        // Recurse up the tree until parent is null, then we've found our root.
+        var parentToken: WindowContainerToken? = rootCandidate.parent
+        while (parentToken != null) {
+            rootCandidate = transitionInfo.getChange(parentToken) ?: break
+            parentToken = rootCandidate.parent
+        }
+
+        // Make sure nothing weird happened, like getChange() returning null.
+        check(rootCandidate != null) { "Failed to find a root leash" }
+
+        // Create a new floating view in Launcher, positioned above the launching icon
+        val drawableArea = launchingIconView.iconDrawableArea
+        val appIcon = appInfo.newIcon(launchingIconView.context)
+        appIcon.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+
+        val floatingView =
+            FloatingAppPairView.getFloatingAppPairView(
+                launcher,
+                drawableArea,
+                appIcon,
+                null /*appIcon2*/,
+                0 /*dividerPos*/
+            )
+        floatingView.bringToFront()
+        launchAnimation.play(
+            getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+        )
+        launchAnimation.start()
+    }
+
+    private fun getIconLaunchValueAnimator(
+        t: Transaction,
+        dp: com.android.launcher3.DeviceProfile,
+        finishCallback: Runnable,
+        launcher: QuickstepLauncher,
+        floatingView: FloatingAppPairView,
+        rootCandidate: Change
+    ): ValueAnimator {
+        val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
+        val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
+        progressUpdater.setDuration(timings.getDuration().toLong())
+        progressUpdater.interpolator = Interpolators.LINEAR
+
         // Shell animation: the apps are revealed toward end of the launch animation
         progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
             val progress =
@@ -706,23 +895,6 @@
             t.apply()
         }
 
-        // Create a new floating view in Launcher, positioned above the launching icon
-        val drawableArea = launchingIconView.iconDrawableArea
-        val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
-        val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
-        appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
-        appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
-        val floatingView =
-            FloatingAppPairView.getFloatingAppPairView(
-                launcher,
-                drawableArea,
-                appIcon1,
-                appIcon2,
-                dividerPos
-            )
-        floatingView.bringToFront()
-
-        // Launcher animation: animate the floating view, expanding to fill the display surface
         progressUpdater.addUpdateListener(
             object : MultiValueUpdateListener() {
                 var mDx =
@@ -776,8 +948,6 @@
                 }
             }
         )
-
-        // When animation ends, remove the floating view and run finishCallback
         progressUpdater.addListener(
             object : AnimatorListenerAdapter() {
                 override fun onAnimationEnd(animation: Animator) {
@@ -787,19 +957,20 @@
             }
         )
 
-        launchAnimation.play(progressUpdater)
-        launchAnimation.start()
+        return progressUpdater
     }
 
     /**
      * This is a scale-up-and-fade-in animation (34% to 100%) for launching an app in Overview when
-     * there is no visible associated tile to expand from.
+     * there is no visible associated tile to expand from. [windowingMode] helps determine whether
+     * we are looking for a split or a single fullscreen [Change]
      */
     @VisibleForTesting
     fun composeScaleUpLaunchAnimation(
         transitionInfo: TransitionInfo,
         t: Transaction,
-        finishCallback: Runnable
+        finishCallback: Runnable,
+        windowingMode: Int
     ) {
         val launchAnimation = AnimatorSet()
         val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
@@ -813,9 +984,8 @@
 
             // TODO (b/316490565): Replace this logic when SplitBounds is available to
             //  startAnimation() and we can know the precise taskIds of launching tasks.
-            // Find a change that has WINDOWING_MODE_MULTI_WINDOW.
             if (
-                taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
+                taskInfo.windowingMode == windowingMode &&
                     (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)
             ) {
                 // Found one!
@@ -947,12 +1117,12 @@
         animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
         animator.addUpdateListener { valueAnimator: ValueAnimator ->
             val progress =
-                    Interpolators.clampToProgress(
-                            Interpolators.LINEAR,
-                            valueAnimator.animatedFraction,
-                            0.8f,
-                            1f
-                    )
+                Interpolators.clampToProgress(
+                    Interpolators.LINEAR,
+                    valueAnimator.animatedFraction,
+                    0.8f,
+                    1f
+                )
             for (leash in openingTargets) {
                 animTransaction.setAlpha(leash, progress)
             }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 06edb14..8258ab8 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -38,36 +38,40 @@
 import java.io.PrintWriter
 
 /**
- * Holds/transforms/signs/seals/delivers information for the transient state of the user
- * selecting a first app to start split with and then choosing a second app.
- * This class DOES NOT associate itself with drag-and-drop split screen starts because they come
- * from the bad part of town.
+ * Holds/transforms/signs/seals/delivers information for the transient state of the user selecting a
+ * first app to start split with and then choosing a second app. This class DOES NOT associate
+ * itself with drag-and-drop split screen starts because they come from the bad part of town.
  *
  * After setting the correct fields for initial/second.* variables, this converts them into the
- * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary
- * data back via [getSplitLaunchData]. Note: there should be only one "initial" field and one
- * "second" field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are
- * always passed in together as a set, and are converted to a single [PendingIntent] or
+ * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary data
+ * back via [getSplitLaunchData]. Note: there should be only one "initial" field and one "second"
+ * field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are always passed
+ * in together as a set, and are converted to a single [PendingIntent] or
  * [ShortcutInfo]+[PendingIntent] before launch.)
  *
  * [SplitLaunchType] indicates the type of tasks/apps/intents being launched given the provided
  * state
  */
-class SplitSelectDataHolder(
-        var context: Context?
-) {
+class SplitSelectDataHolder(var context: Context?) {
     val TAG = SplitSelectDataHolder::class.simpleName
 
     /**
-     * Order of the constant indicates the order of which task/app was selected.
-     * Ex. SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut
+     * Order of the constant indicates the order of which task/app was selected. Ex.
+     * SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut
      * SPLIT_SHORTCUT_TASK means primary split app is determined by shortcut, secondary is task
      */
     companion object {
-        @IntDef(SPLIT_TASK_TASK, SPLIT_TASK_PENDINGINTENT, SPLIT_TASK_SHORTCUT,
-                SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK,
-                SPLIT_SINGLE_TASK_FULLSCREEN, SPLIT_SINGLE_INTENT_FULLSCREEN,
-                SPLIT_SINGLE_SHORTCUT_FULLSCREEN)
+        @IntDef(
+            SPLIT_TASK_TASK,
+            SPLIT_TASK_PENDINGINTENT,
+            SPLIT_TASK_SHORTCUT,
+            SPLIT_PENDINGINTENT_TASK,
+            SPLIT_PENDINGINTENT_PENDINGINTENT,
+            SPLIT_SHORTCUT_TASK,
+            SPLIT_SINGLE_TASK_FULLSCREEN,
+            SPLIT_SINGLE_INTENT_FULLSCREEN,
+            SPLIT_SINGLE_SHORTCUT_FULLSCREEN
+        )
         @Retention(AnnotationRetention.SOURCE)
         annotation class SplitLaunchType
 
@@ -84,8 +88,7 @@
         const val SPLIT_SINGLE_SHORTCUT_FULLSCREEN = 8
     }
 
-    @StagePosition
-    private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+    @StagePosition private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
     private var itemInfo: ItemInfo? = null
     private var secondItemInfo: ItemInfo? = null
     private var splitEvent: EventEnum? = null
@@ -108,12 +111,16 @@
 
     /**
      * @param alreadyRunningTask if set to [android.app.ActivityTaskManager.INVALID_TASK_ID]
-     * then @param intent will be used to launch the initial task
+     *   then @param intent will be used to launch the initial task
      * @param intent will be ignored if @param alreadyRunningTask is set
      */
-    fun setInitialTaskSelect(intent: Intent?, @StagePosition stagePosition: Int,
-                             itemInfo: ItemInfo?, splitEvent: EventEnum?,
-                             alreadyRunningTask: Int) {
+    fun setInitialTaskSelect(
+        intent: Intent?,
+        @StagePosition stagePosition: Int,
+        itemInfo: ItemInfo?,
+        splitEvent: EventEnum?,
+        alreadyRunningTask: Int
+    ) {
         if (alreadyRunningTask != INVALID_TASK_ID) {
             initialTaskId = alreadyRunningTask
         } else {
@@ -127,15 +134,21 @@
      * To be called after first task selected from using a split shortcut from the fullscreen
      * running app.
      */
-    fun setInitialTaskSelect(info: RunningTaskInfo,
-                             @StagePosition stagePosition: Int, itemInfo: ItemInfo?,
-                             splitEvent: EventEnum?) {
+    fun setInitialTaskSelect(
+        info: RunningTaskInfo,
+        @StagePosition stagePosition: Int,
+        itemInfo: ItemInfo?,
+        splitEvent: EventEnum?
+    ) {
         initialTaskId = info.taskId
         setInitialData(stagePosition, splitEvent, itemInfo)
     }
 
-    private fun setInitialData(@StagePosition stagePosition: Int,
-                               event: EventEnum?, item: ItemInfo?) {
+    private fun setInitialData(
+        @StagePosition stagePosition: Int,
+        event: EventEnum?,
+        item: ItemInfo?
+    ) {
         itemInfo = item
         initialStagePosition = stagePosition
         splitEvent = event
@@ -143,6 +156,7 @@
 
     /**
      * To be called as soon as user selects the second task (even if animations aren't complete)
+     *
      * @param taskId The second task that will be launched.
      */
     fun setSecondTask(taskId: Int, itemInfo: ItemInfo) {
@@ -152,6 +166,7 @@
 
     /**
      * To be called as soon as user selects the second app (even if animations aren't complete)
+     *
      * @param intent The second intent that will be launched.
      * @param user The user of that intent.
      */
@@ -162,8 +177,9 @@
     }
 
     /**
-     * To be called as soon as user selects the second app (even if animations aren't complete)
-     * Sets [secondUser] from that of the pendingIntent
+     * To be called as soon as user selects the second app (even if animations aren't complete) Sets
+     * [secondUser] from that of the pendingIntent
+     *
      * @param pendingIntent The second PendingIntent that will be launched.
      */
     fun setSecondTask(pendingIntent: PendingIntent, itemInfo: ItemInfo) {
@@ -173,9 +189,9 @@
     }
 
     /**
-     * Similar to [setSecondTask] except this is to be called for widgets which can pass through
-     * an extra intent from their RemoteResponse.
-     * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
+     * Similar to [setSecondTask] except this is to be called for widgets which can pass through an
+     * extra intent from their RemoteResponse. See
+     * [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
      */
     fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?, itemInfo: ItemInfo) {
         setSecondTask(pendingIntent, itemInfo)
@@ -184,8 +200,7 @@
 
     private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
         val intentPackage = intent?.getPackage() ?: return null
-        val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
-                ?: return null
+        val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) ?: return null
         try {
             val context: Context =
                 if (user != null) {
@@ -200,9 +215,7 @@
         return null
     }
 
-    /**
-     * Converts intents to pendingIntents, associating the [user] with the intent if provided
-     */
+    /** Converts intents to pendingIntents, associating the [user] with the intent if provided */
     private fun getPendingIntent(intent: Intent?, user: UserHandle?): PendingIntent? {
         if (intent != initialIntent && intent != secondIntent) {
             throw IllegalStateException("Invalid intent to convert to PendingIntent")
@@ -211,12 +224,21 @@
         return if (intent == null) {
             null
         } else if (user != null) {
-            PendingIntent.getActivityAsUser(context, 0, intent,
-                    PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
-                    null /* options */, user)
+            PendingIntent.getActivityAsUser(
+                context,
+                0,
+                intent,
+                PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
+                null /* options */,
+                user
+            )
         } else {
-            PendingIntent.getActivity(context, 0, intent,
-                    PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)
+            PendingIntent.getActivity(
+                context,
+                0,
+                intent,
+                PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
+            )
         }
     }
 
@@ -224,7 +246,7 @@
      * @return [SplitLaunchData] with the necessary fields populated as determined by
      *   [SplitLaunchData.splitLaunchType]. This is to be used for launching splitscreen
      */
-    fun getSplitLaunchData() : SplitLaunchData {
+    fun getSplitLaunchData(): SplitLaunchData {
         // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
         convertIntentsToFinalTypes()
         val splitLaunchType = getSplitLaunchType()
@@ -241,7 +263,7 @@
      *   [SplitLaunchData.splitLaunchType]. This is to be used for launching an initially selected
      *   split task in fullscreen
      */
-    fun getFullscreenLaunchData() : SplitLaunchData {
+    fun getFullscreenLaunchData(): SplitLaunchData {
         // Convert all intents to shortcut infos to determine if we launch shortcut or intent
         convertIntentsToFinalTypes()
         val splitLaunchType = getFullscreenLaunchType()
@@ -249,21 +271,22 @@
         return generateSplitLaunchData(splitLaunchType)
     }
 
-    private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int) : SplitLaunchData {
+    private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int): SplitLaunchData {
         return SplitLaunchData(
-                splitLaunchType,
-                initialTaskId,
-                secondTaskId,
-                initialPendingIntent,
-                secondPendingIntent,
-                widgetSecondIntent,
-                initialUser?.identifier ?: -1,
-                secondUser?.identifier ?: -1,
-                initialShortcut,
-                secondShortcut,
-                itemInfo,
-                splitEvent,
-                initialStagePosition)
+            splitLaunchType,
+            initialTaskId,
+            secondTaskId,
+            initialPendingIntent,
+            secondPendingIntent,
+            widgetSecondIntent,
+            initialUser?.identifier ?: -1,
+            secondUser?.identifier ?: -1,
+            initialShortcut,
+            secondShortcut,
+            itemInfo,
+            splitEvent,
+            initialStagePosition
+        )
     }
 
     /**
@@ -273,8 +296,7 @@
      * Note that both [initialIntent] and [secondIntent] will be nullified on method return
      *
      * One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
-     * convert [secondIntent].
-     * This also leaves [widgetSecondIntent] untouched.
+     * convert [secondIntent]. This also leaves [widgetSecondIntent] untouched.
      */
     private fun convertIntentsToFinalTypes() {
         initialShortcut = getShortcutInfo(initialIntent, initialUser)
@@ -297,8 +319,8 @@
     }
 
     /**
-     * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents
-     * Intents need to be converted in [convertIntentsToFinalTypes] prior to calling this method
+     * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents Intents
+     * need to be converted in [convertIntentsToFinalTypes] prior to calling this method
      */
     @VisibleForTesting
     @SplitLaunchType
@@ -354,41 +376,40 @@
     }
 
     data class SplitLaunchData(
-            @SplitLaunchType
-            val splitLaunchType: Int,
-            var initialTaskId: Int = INVALID_TASK_ID,
-            var secondTaskId: Int = INVALID_TASK_ID,
-            var initialPendingIntent: PendingIntent? = null,
-            var secondPendingIntent: PendingIntent? = null,
-            var widgetSecondIntent: Intent? = null,
-            var initialUserId: Int = -1,
-            var secondUserId: Int = -1,
-            var initialShortcut: ShortcutInfo? = null,
-            var secondShortcut: ShortcutInfo? = null,
-            var itemInfo: ItemInfo? = null,
-            var splitEvent: EventEnum? = null,
-            val initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+        @SplitLaunchType val splitLaunchType: Int,
+        var initialTaskId: Int = INVALID_TASK_ID,
+        var secondTaskId: Int = INVALID_TASK_ID,
+        var initialPendingIntent: PendingIntent? = null,
+        var secondPendingIntent: PendingIntent? = null,
+        var widgetSecondIntent: Intent? = null,
+        var initialUserId: Int = -1,
+        var secondUserId: Int = -1,
+        var initialShortcut: ShortcutInfo? = null,
+        var secondShortcut: ShortcutInfo? = null,
+        var itemInfo: ItemInfo? = null,
+        var splitEvent: EventEnum? = null,
+        val initialStagePosition: Int = STAGE_POSITION_UNDEFINED
     )
 
     /**
-     * @return `true` if first task has been selected and waiting for the second task to be
-     * chosen
+     * @return `true` if first task has been selected and waiting for the second task to be chosen
      */
     fun isSplitSelectActive(): Boolean {
         return isInitialTaskIntentSet() && !isSecondTaskIntentSet()
     }
 
     /**
-     * @return `true` if the first and second task have been chosen and split is waiting to
-     * be launched
+     * @return `true` if the first and second task have been chosen and split is waiting to be
+     *   launched
      */
     fun isBothSplitAppsConfirmed(): Boolean {
         return isInitialTaskIntentSet() && isSecondTaskIntentSet()
     }
 
     private fun isInitialTaskIntentSet(): Boolean {
-        return initialTaskId != INVALID_TASK_ID || initialIntent != null ||
-                initialPendingIntent != null
+        return initialTaskId != INVALID_TASK_ID ||
+            initialIntent != null ||
+            initialPendingIntent != null
     }
 
     fun getInitialTaskId(): Int {
@@ -416,8 +437,9 @@
     }
 
     private fun isSecondTaskIntentSet(): Boolean {
-        return secondTaskId != INVALID_TASK_ID || secondIntent != null
-                || secondPendingIntent != null
+        return secondTaskId != INVALID_TASK_ID ||
+            secondIntent != null ||
+            secondPendingIntent != null
     }
 
     fun resetState() {
@@ -437,7 +459,7 @@
     }
 
     fun dump(prefix: String, writer: PrintWriter) {
-        writer.println("$prefix ${javaClass.simpleName}")
+        writer.println("$prefix SplitSelectDataHolder")
         writer.println("$prefix\tinitialStagePosition= $initialStagePosition")
         writer.println("$prefix\tinitialTaskId= $initialTaskId")
         writer.println("$prefix\tsecondTaskId= $secondTaskId")
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index c257be6..df1879e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -90,7 +90,6 @@
 import com.android.quickstep.OverviewComponentObserver;
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.RecentsAnimationController;
-import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.RecentsAnimationTargets;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SplitSelectionListener;
@@ -646,8 +645,13 @@
         }
     }
 
-    public void initSplitFromDesktopController(QuickstepLauncher launcher) {
-        initSplitFromDesktopController(new SplitFromDesktopController(launcher));
+    /**
+     * Init {@code SplitFromDesktopController}
+     */
+    public void initSplitFromDesktopController(QuickstepLauncher launcher,
+            OverviewComponentObserver overviewComponentObserver) {
+        initSplitFromDesktopController(
+                new SplitFromDesktopController(launcher, overviewComponentObserver));
     }
 
     @VisibleForTesting
@@ -956,12 +960,10 @@
         private ISplitSelectListener mSplitSelectListener;
         private Drawable mAppIcon;
 
-        public SplitFromDesktopController(QuickstepLauncher launcher) {
+        public SplitFromDesktopController(QuickstepLauncher launcher,
+                OverviewComponentObserver overviewComponentObserver) {
             mLauncher = launcher;
-            RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
-                    launcher.getApplicationContext());
-            mOverviewComponentObserver =
-                    new OverviewComponentObserver(launcher.getApplicationContext(), deviceState);
+            mOverviewComponentObserver = overviewComponentObserver;
             mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
                     R.dimen.split_placeholder_size);
             mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index b6e6bf7..2396512 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -63,7 +63,7 @@
             SplitSelectStateController controller) {
         mLauncher = launcher;
         mController = controller;
-        mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache();
+        mIconCache = LauncherAppState.getInstance(launcher).getIconCache();
         mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.multi_window_task_divider_size) / 2;
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 555bf21..85d4f4b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -62,12 +62,13 @@
     private final int mSplitPlaceholderInset;
 
     public SplitWithKeyboardShortcutController(QuickstepLauncher launcher,
-            SplitSelectStateController controller) {
+            SplitSelectStateController controller,
+            OverviewComponentObserver overviewComponentObserver,
+            RecentsAnimationDeviceState deviceState) {
         mLauncher = launcher;
         mController = controller;
-        mDeviceState = new RecentsAnimationDeviceState(launcher.getApplicationContext());
-        mOverviewComponentObserver = new OverviewComponentObserver(launcher.getApplicationContext(),
-                mDeviceState);
+        mDeviceState = deviceState;
+        mOverviewComponentObserver = overviewComponentObserver;
 
         mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.split_placeholder_size);
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 6c89be1..99f10a7 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -46,7 +46,7 @@
  * when swiping up (in gesture navigation mode).
  */
 public class SwipePipToHomeAnimator extends RectFSpringAnim {
-    private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
+    private static final String TAG = "SwipePipToHomeAnimator";
 
     private static final float END_PROGRESS = 1.0f;
 
@@ -112,7 +112,7 @@
             @NonNull ActivityInfo activityInfo,
             int appIconSizePx,
             @NonNull SurfaceControl leash,
-            @Nullable Rect sourceRectHint,
+            @NonNull Rect sourceRectHint,
             @NonNull Rect appBounds,
             @NonNull Matrix homeToWindowPositionMap,
             @NonNull RectF startBounds,
@@ -135,22 +135,25 @@
         mDestinationBoundsTransformed.set(destinationBoundsTransformed);
         mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(cornerRadius, shadowRadius);
 
-        if (sourceRectHint != null && (sourceRectHint.width() < destinationBounds.width()
-                || sourceRectHint.height() < destinationBounds.height())) {
+        String reasonForCreateOverlay = null; // For debugging purpose.
+        if (sourceRectHint.isEmpty()) {
+            reasonForCreateOverlay = "Source rect hint is empty";
+        } else if (sourceRectHint.width() < destinationBounds.width()
+                || sourceRectHint.height() < destinationBounds.height()) {
             // This is a situation in which the source hint rect on at least one axis is smaller
             // than the destination bounds, which presents a problem because we would have to scale
             // up that axis to fit the bounds. So instead, just fallback to the non-source hint
             // animation in this case.
-            sourceRectHint = null;
-        }
-
-        if (sourceRectHint != null && !appBounds.contains(sourceRectHint)) {
+            reasonForCreateOverlay = "Source rect hint is too small " + sourceRectHint;
+            sourceRectHint.setEmpty();
+        } else if (!appBounds.contains(sourceRectHint)) {
             // This is a situation in which the source hint rect is outside the app bounds, so it is
             // not a valid rectangle to use for cropping app surface
-            sourceRectHint = null;
+            sourceRectHint.setEmpty();
+            reasonForCreateOverlay = "Source rect hint exceeds display bounds " + sourceRectHint;
         }
 
-        if (sourceRectHint == null) {
+        if (sourceRectHint.isEmpty()) {
             mSourceRectHint.setEmpty();
             mSourceHintRectInsets = null;
 
@@ -162,6 +165,7 @@
                     new IconProvider(context).getIcon(mActivityInfo), appIconSizePx);
             final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
             mPipContentOverlay.attach(tx, mLeash);
+            Log.d(TAG, getContentOverlay() + " is created: " + reasonForCreateOverlay);
         } else {
             mSourceRectHint.set(sourceRectHint);
             mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 9268511..304b8f4 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -26,9 +26,11 @@
 import android.view.WindowMetrics;
 
 import com.android.internal.policy.SystemBarUtils;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.CachedDisplayInfo;
 import com.android.launcher3.util.window.WindowManagerProxy;
+import com.android.quickstep.LauncherActivityInterface;
 
 import java.util.List;
 import java.util.Set;
@@ -49,6 +51,13 @@
     }
 
     @Override
+    public boolean isInDesktopMode() {
+        DesktopVisibilityController desktopController =
+                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+        return desktopController != null && desktopController.areDesktopTasksVisible();
+    }
+
+    @Override
     public int getRotation(Context displayInfoContext) {
         return displayInfoContext.getResources().getConfiguration().windowConfiguration
                 .getRotation();
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
index 21c9e09..69137cc 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
@@ -37,7 +37,7 @@
  * @param <V> Type of object stored in the cache
  */
 public class TaskKeyByLastActiveTimeCache<V> implements TaskKeyCache<V> {
-    private static final String TAG = TaskKeyByLastActiveTimeCache.class.getSimpleName();
+    private static final String TAG = "TaskKeyByLastActiveTimeCache";
     private final AtomicInteger mMaxSize;
     private final Map<Integer, Entry<V>> mMap;
     // To sort task id by last active time
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index 89d8cc4..e80d2a6 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -22,6 +22,8 @@
 import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
 import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
 
+import android.content.Context;
+
 import androidx.annotation.NonNull;
 
 import com.android.quickstep.RecentsModel;
@@ -45,6 +47,12 @@
     private final Runnable mUnregisterCallback = this::unregister;
     private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
 
+    private final Context mContext;
+
+    public TaskRemovedDuringLaunchListener(Context context) {
+        mContext = context;
+    }
+
     /**
      * Registers a failure listener callback if it detects a scenario in which an app launch
      * failed before the transition finished.
@@ -88,7 +96,7 @@
         if (mLaunchedTaskId != INVALID_TASK_ID) {
             final int launchedTaskId = mLaunchedTaskId;
             final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
-            RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
+            RecentsModel.INSTANCE.get(mContext).isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
                 if (taskRemoved) {
                     ActiveGestureLog.INSTANCE.addLog(
                             new ActiveGestureLog.CompoundString("Launch failed, task (id=")
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index fcb865f..9da4985 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -245,7 +245,7 @@
         if (mSplitBounds == null) {
             mStagePosition = STAGE_POSITION_UNDEFINED;
         } else {
-            mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds)
+            mStagePosition = runningTarget.taskId == splitInfo.leftTopTaskId
                     ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
             mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
                     mStagePosition);
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index b8afd9d..c3efc3c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
 import com.android.launcher3.R;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.BorderAnimator;
 
@@ -136,6 +135,10 @@
      * Enable or disable showing border on focus change
      */
     public void setBorderEnabled(boolean enabled) {
+        if (mBorderEnabled == enabled) {
+            return;
+        }
+
         mBorderEnabled = enabled;
         if (mFocusBorderAnimator != null) {
             mFocusBorderAnimator.setBorderVisibility(/* visible= */
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
deleted file mode 100644
index 78b1763..0000000
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.views;
-
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RoundRectShape;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.desktop.DesktopRecentsTransitionController;
-import com.android.launcher3.icons.IconProvider;
-import com.android.launcher3.util.CancellableTask;
-import com.android.launcher3.util.RunnableList;
-import com.android.quickstep.RecentsModel;
-import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.util.RecentsOrientedState;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.QuickStepContract;
-
-import kotlin.Unit;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * TaskView that contains all tasks that are part of the desktop.
- */
-// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
-public class DesktopTaskView extends TaskView {
-
-    private static final String TAG = DesktopTaskView.class.getSimpleName();
-
-    private static final boolean DEBUG = false;
-
-    @NonNull
-    private List<Task> mTasks = new ArrayList<>();
-
-    private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
-
-    /** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */
-    private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>();
-
-    private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
-
-    private final TaskView.FullscreenDrawParams mSnapshotDrawParams;
-
-    private View mBackgroundView;
-
-    private int mChildCountAtInflation;
-
-    public DesktopTaskView(Context context) {
-        this(context, null);
-    }
-
-    public DesktopTaskView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DesktopTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mSnapshotDrawParams = new FullscreenDrawParams(context) {
-            @Override
-            public float computeTaskCornerRadius(Context context) {
-                return QuickStepContract.getWindowCornerRadius(context);
-            }
-
-            @Override
-            public float computeWindowCornerRadius(Context context) {
-                return QuickStepContract.getWindowCornerRadius(context);
-            }
-        };
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mBackgroundView = findViewById(R.id.background);
-
-        int topMarginPx =
-                mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
-        FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams();
-        params.topMargin = topMarginPx;
-        mBackgroundView.setLayoutParams(params);
-
-        float[] outerRadii = new float[8];
-        Arrays.fill(outerRadii, getTaskCornerRadius());
-        RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
-        ShapeDrawable background = new ShapeDrawable(shape);
-        background.setTint(getResources().getColor(android.R.color.system_neutral2_300,
-                getContext().getTheme()));
-        // TODO(b/244348395): this should be wallpaper
-        mBackgroundView.setBackground(background);
-
-        Drawable icon = getResources().getDrawable(R.drawable.ic_desktop, getContext().getTheme());
-        Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
-                getContext().getTheme());
-        mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
-
-        mChildCountAtInflation = getChildCount();
-    }
-
-    @Override
-    protected Unit updateBorderBounds(@NonNull Rect bounds) {
-        bounds.set(mBackgroundView.getLeft(), mBackgroundView.getTop(), mBackgroundView.getRight(),
-                mBackgroundView.getBottom());
-        return Unit.INSTANCE;
-    }
-
-    @Override
-    public void bind(Task task, RecentsOrientedState orientedState) {
-        bind(Collections.singletonList(task), orientedState);
-    }
-
-    /**
-     * Updates this desktop task to the gives task list defined in {@code tasks}
-     */
-    public void bind(List<Task> tasks, RecentsOrientedState orientedState) {
-        if (DEBUG) {
-            StringBuilder sb = new StringBuilder();
-            sb.append("bind tasks=").append(tasks.size()).append("\n");
-            for (Task task : tasks) {
-                sb.append(" key=").append(task.key).append("\n");
-            }
-            Log.d(TAG, sb.toString());
-        }
-        cancelPendingLoadTasks();
-
-        mTasks = new ArrayList<>(tasks);
-        mSnapshotViewMap.clear();
-
-        // Ensure there are equal number of snapshot views and tasks.
-        // More tasks than views, add views. More views than tasks, remove views.
-        // TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews
-        if (mSnapshotViews.size() > mTasks.size()) {
-            int diff = mSnapshotViews.size() - mTasks.size();
-            for (int i = 0; i < diff; i++) {
-                TaskThumbnailView snapshotView = mSnapshotViews.remove(0);
-                removeView(snapshotView);
-            }
-        } else if (mSnapshotViews.size() < mTasks.size()) {
-            int diff = mTasks.size() - mSnapshotViews.size();
-            for (int i = 0; i < diff; i++) {
-                TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
-                mSnapshotViews.add(snapshotView);
-                // Add snapshots from to position after the initial child views.
-                addView(snapshotView, mChildCountAtInflation,
-                        new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-            }
-        }
-
-        for (int i = 0; i < mTasks.size(); i++) {
-            Task task = mTasks.get(i);
-            TaskThumbnailView snapshotView = mSnapshotViews.get(i);
-            snapshotView.bind(task);
-            mSnapshotViewMap.put(task.key.id, snapshotView);
-        }
-
-        updateTaskIdContainer();
-        updateTaskIdAttributeContainer();
-
-        setOrientationState(orientedState);
-    }
-
-    private void updateTaskIdContainer() {
-        // TODO(b/249371338): TaskView expects the array to have at least 2 elements.
-        // At least 2 elements in the array
-        mTaskIdContainer = new int[Math.max(mTasks.size(), 2)];
-        for (int i = 0; i < mTasks.size(); i++) {
-            mTaskIdContainer[i] = mTasks.get(i).key.id;
-        }
-    }
-
-    private void updateTaskIdAttributeContainer() {
-        // TODO(b/249371338): TaskView expects the array to have at least 2 elements.
-        // At least 2 elements in the array
-        mTaskIdAttributeContainer = new TaskIdAttributeContainer[Math.max(mTasks.size(), 2)];
-        for (int i = 0; i < mTasks.size(); i++) {
-            Task task = mTasks.get(i);
-            TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
-            mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
-        }
-    }
-
-    private TaskIdAttributeContainer createAttributeContainer(Task task,
-            TaskThumbnailView thumbnailView) {
-        return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
-                STAGE_POSITION_UNDEFINED);
-    }
-
-    private IconView createIconView(Task task) {
-        IconView iconView = new IconView(mContext);
-        PackageManager pm = mContext.getApplicationContext().getPackageManager();
-        try {
-            IconProvider provider = new IconProvider(mContext);
-            Drawable appIcon = provider.getIcon(pm.getActivityInfo(task.topActivity,
-                    PackageManager.ComponentInfoFlags.of(0)));
-            iconView.setDrawable(appIcon);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Package not found: " + task.topActivity.getPackageName(), e);
-        }
-        return iconView;
-    }
-
-    @Nullable
-    @Override
-    public Task getTask() {
-        // TODO(b/249371338): returning first task. This won't work well with multiple tasks.
-        return mTasks.size() > 0 ? mTasks.get(0) : null;
-    }
-
-    @Override
-    public TaskThumbnailView getThumbnail() {
-        // TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks.
-        Task task = getTask();
-        if (task != null) {
-            return mSnapshotViewMap.get(task.key.id);
-        }
-        // Return the place holder snapshot views. Callers expect this to be non-null
-        return mSnapshotView;
-    }
-
-    @Override
-    public boolean containsTaskId(int taskId) {
-        // Thumbnail map contains taskId -> thumbnail map. Use the keys for contains
-        return mSnapshotViewMap.contains(taskId);
-    }
-
-    @Override
-    public void onTaskListVisibilityChanged(boolean visible, int changes) {
-        cancelPendingLoadTasks();
-        if (visible) {
-            RecentsModel model = RecentsModel.INSTANCE.get(getContext());
-            TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
-
-            if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
-                for (Task task : mTasks) {
-                    CancellableTask<?> thumbLoadRequest =
-                            thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
-                                TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
-                                if (thumbnailView != null) {
-                                    thumbnailView.setThumbnail(task, thumbnailData);
-                                }
-                            });
-                    if (thumbLoadRequest != null) {
-                        mPendingThumbnailRequests.add(thumbLoadRequest);
-                    }
-                }
-            }
-        } else {
-            if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
-                for (Task task : mTasks) {
-                    TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
-                    if (thumbnailView != null) {
-                        thumbnailView.setThumbnail(null, null);
-                    }
-                    // Reset the task thumbnail ref
-                    task.thumbnail = null;
-                }
-            }
-        }
-    }
-
-    @Override
-    protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
-        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
-        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-
-        LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
-        snapshotParams.topMargin = thumbnailTopMargin;
-
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
-            thumbnailView.setLayoutParams(snapshotParams);
-        }
-    }
-
-    @Override
-    protected void cancelPendingLoadTasks() {
-        for (CancellableTask<?> cancellableTask : mPendingThumbnailRequests) {
-            cancellableTask.cancel();
-        }
-        mPendingThumbnailRequests.clear();
-    }
-
-    @Override
-    public boolean offerTouchToChildren(MotionEvent event) {
-        return false;
-    }
-
-    @Override
-    protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
-        return false;
-    }
-
-    @Nullable
-    @Override
-    public RunnableList launchTaskAnimated() {
-        RunnableList endCallback = new RunnableList();
-
-        RecentsView recentsView = getRecentsView();
-        DesktopRecentsTransitionController recentsController =
-                recentsView.getDesktopRecentsController();
-        if (recentsController != null) {
-            recentsController.launchDesktopFromRecents(this, success -> {
-                endCallback.executeAllAndDestroy();
-            });
-        }
-
-        // Callbacks get run from recentsView for case when recents animation already running
-        recentsView.addSideTaskLaunchCallback(endCallback);
-        return endCallback;
-    }
-
-    @Override
-    public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
-        launchTasks();
-        callback.accept(true);
-    }
-
-    @Override
-    public boolean isDesktopTask() {
-        return true;
-    }
-
-    @Override
-    void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
-        // Sets new thumbnails based on the incoming data and refreshes the rest.
-        // Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
-        SparseArray<TaskThumbnailView> thumbnailsToRefresh = mSnapshotViewMap.clone();
-        if (thumbnailDatas != null) {
-            for (Task task : mTasks) {
-                int key = task.key.id;
-                TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key);
-                ThumbnailData thumbnailData = thumbnailDatas.get(key);
-                if (thumbnailView != null && thumbnailData != null) {
-                    thumbnailView.setThumbnail(task, thumbnailData);
-                    // Remove this thumbnail from the list that should be refreshed.
-                    thumbnailsToRefresh.remove(key);
-                }
-            }
-        }
-
-        // Refresh the rest that were not updated.
-        for (int i = 0; i < thumbnailsToRefresh.size(); i++) {
-            thumbnailsToRefresh.valueAt(i).refresh();
-        }
-    }
-
-    @Override
-    public TaskThumbnailView[] getThumbnails() {
-        TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()];
-        for (int i = 0; i < thumbnails.length; i++) {
-            thumbnails[i] = mSnapshotViewMap.valueAt(i);
-        }
-        return thumbnails;
-    }
-
-    @Override
-    public void onRecycle() {
-        resetPersistentViewTransforms();
-        // Clear any references to the thumbnail (it will be re-read either from the cache or the
-        // system on next bind)
-        for (Task task : mTasks) {
-            TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
-            if (thumbnailView != null) {
-                thumbnailView.setThumbnail(task, null);
-            }
-        }
-        setOverlayEnabled(false);
-        onTaskListVisibilityChanged(false);
-        setVisibility(VISIBLE);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int containerWidth = MeasureSpec.getSize(widthMeasureSpec);
-        int containerHeight = MeasureSpec.getSize(heightMeasureSpec);
-
-        setMeasuredDimension(containerWidth, containerHeight);
-
-        int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
-        containerHeight -= thumbnailTopMarginPx;
-
-        int thumbnails = mSnapshotViewMap.size();
-        if (thumbnails == 0) {
-            return;
-        }
-
-        int windowWidth = mContainer.getDeviceProfile().widthPx;
-        int windowHeight = mContainer.getDeviceProfile().heightPx;
-
-        float scaleWidth = containerWidth / (float) windowWidth;
-        float scaleHeight = containerHeight / (float) windowHeight;
-
-        if (DEBUG) {
-            Log.d(TAG,
-                    "onMeasure: container=[" + containerWidth + "," + containerHeight + "] window=["
-                            + windowWidth + "," + windowHeight + "] scale=[" + scaleWidth + ","
-                            + scaleHeight + "]");
-        }
-
-        // Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
-        for (int i = 0; i < mTasks.size(); i++) {
-            Task task = mTasks.get(i);
-            Rect taskSize = task.appBounds;
-            if (taskSize == null) {
-                // Default to quarter of the desktop if we did not get app bounds.
-                taskSize = new Rect(0, 0, windowWidth / 4, windowHeight / 4);
-            }
-
-            int thumbWidth = (int) (taskSize.width() * scaleWidth);
-            int thumbHeight = (int) (taskSize.height() * scaleHeight);
-
-            TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
-            if (thumbnailView != null) {
-                thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
-                        MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
-
-                // Position the task to the same position as it would be on the desktop
-                Point positionInParent = task.positionInParent;
-                if (positionInParent == null) {
-                    positionInParent = new Point(0, 0);
-                }
-                int taskX = (int) (positionInParent.x * scaleWidth);
-                int taskY = (int) (positionInParent.y * scaleHeight);
-                // move task down by margin size
-                taskY += thumbnailTopMarginPx;
-                thumbnailView.setX(taskX);
-                thumbnailView.setY(taskY);
-
-                if (DEBUG) {
-                    Log.d(TAG, "onMeasure: task=" + task.key + " thumb=[" + thumbWidth + ","
-                            + thumbHeight + "]" + " pos=[" + taskX + "," + taskY + "]");
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setOverlayEnabled(boolean overlayEnabled) {
-        // Intentional no-op to prevent setting smart actions overlay on thumbnails
-    }
-
-    @Override
-    public void setFullscreenProgress(float progress) {
-        // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
-        progress = Utilities.boundToRange(progress, 0, 1);
-        mFullscreenProgress = progress;
-        if (mFullscreenProgress > 0) {
-            // Don't show background while we are transitioning to/from fullscreen
-            mBackgroundView.setVisibility(INVISIBLE);
-        } else {
-            mBackgroundView.setVisibility(VISIBLE);
-        }
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
-            thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
-        }
-        updateSnapshotRadius();
-    }
-
-    @Override
-    protected void updateSnapshotRadius() {
-        super.updateSnapshotRadius();
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            if (i == 0) {
-                // All snapshots share the same params. Only update it with the first snapshot.
-                updateFullscreenParams(mSnapshotDrawParams);
-            }
-            mSnapshotViewMap.valueAt(i).setFullscreenParams(mSnapshotDrawParams);
-        }
-    }
-
-    @Override
-    protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) {
-        // no-op
-    }
-
-    @Override
-    public void setColorTint(float amount, int tintColor) {
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            mSnapshotViewMap.valueAt(i).setDimAlpha(amount);
-        }
-    }
-
-    @Override
-    protected void applyThumbnailSplashAlpha() {
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            mSnapshotViewMap.valueAt(i).setSplashAlpha(mTaskThumbnailSplashAlpha);
-        }
-    }
-
-    @Override
-    void setThumbnailVisibility(int visibility, int taskId) {
-        for (int i = 0; i < mSnapshotViewMap.size(); i++) {
-            mSnapshotViewMap.valueAt(i).setVisibility(visibility);
-        }
-    }
-
-    @Override
-    protected boolean confirmSecondSplitSelectApp() {
-        // Desktop tile can't be in split screen
-        return false;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
new file mode 100644
index 0000000..b7c0236
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views
+
+import android.content.Context
+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
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.LauncherState
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.CancellableTask
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.ViewPool
+import com.android.quickstep.BaseContainerInterface
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.util.RecentsOrientedState
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.QuickStepContract
+import java.util.function.Consumer
+
+/** TaskView that contains all tasks that are part of the desktop. */
+// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
+class DesktopTaskView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) :
+    TaskView(context, attrs) {
+
+    private val pendingThumbnailRequests = mutableListOf<CancellableTask<*>>()
+    private val snapshotDrawParams =
+        object : FullscreenDrawParams(context) {
+            override fun computeTaskCornerRadius(context: Context) =
+                QuickStepContract.getWindowCornerRadius(context)
+
+            override fun computeWindowCornerRadius(context: Context) =
+                QuickStepContract.getWindowCornerRadius(context)
+        }
+    private val taskThumbnailViewPool =
+        ViewPool<TaskThumbnailViewDeprecated>(
+            context,
+            this,
+            R.layout.task_thumbnail,
+            10,
+            0 // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
+        )
+    private val tempPointF = PointF()
+    private val tempRect = Rect()
+    private lateinit var backgroundView: View
+    private var childCountAtInflation = 0
+
+    init {
+        mTaskContainers = ArrayList()
+    }
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+
+        backgroundView = findViewById(R.id.background)!!
+        val topMarginPx = mContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+        backgroundView.updateLayoutParams<LayoutParams> { topMargin = topMarginPx }
+
+        val outerRadii = FloatArray(8) { taskCornerRadius }
+        backgroundView.background =
+            ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
+                setTint(resources.getColor(android.R.color.system_neutral2_300, context.theme))
+            }
+
+        val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme)
+        val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme)
+        setIcon(mIconView, LayerDrawable(arrayOf(iconBackground, icon)))
+
+        childCountAtInflation = childCount
+    }
+
+    override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) {
+        if (relativeToDragLayer) {
+            mContainer.dragLayer.getDescendantRectRelativeToSelf(backgroundView, bounds)
+        } else {
+            bounds.set(
+                backgroundView.left,
+                backgroundView.top,
+                backgroundView.right,
+                backgroundView.bottom
+            )
+        }
+    }
+
+    override fun bind(task: Task, orientedState: RecentsOrientedState) {
+        bind(listOf(task), orientedState)
+    }
+
+    /** Updates this desktop task to the gives task list defined in `tasks` */
+    fun bind(tasks: List<Task>, orientedState: RecentsOrientedState) {
+        if (DEBUG) {
+            val sb = StringBuilder()
+            sb.append("bind tasks=").append(tasks.size).append("\n")
+            tasks.forEach { sb.append(" key=${it.key}\n") }
+            Log.d(TAG, sb.toString())
+        }
+        cancelPendingLoadTasks()
+
+        (mTaskContainers as ArrayList).ensureCapacity(tasks.size)
+        tasks.forEachIndexed { index, task ->
+            val thumbnailView: TaskThumbnailViewDeprecated
+            if (index >= mTaskContainers.size) {
+                thumbnailView = taskThumbnailViewPool.view
+                // Add thumbnailView from to position after the initial child views.
+                addView(
+                    thumbnailView,
+                    childCountAtInflation,
+                    LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT
+                    )
+                )
+            } else {
+                thumbnailView = mTaskContainers[index].thumbnailView
+            }
+            thumbnailView.bind(task)
+            val taskContainer =
+                TaskContainer(
+                    task,
+                    thumbnailView,
+                    mIconView,
+                    SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                    null
+                )
+            if (index >= mTaskContainers.size) {
+                mTaskContainers.add(taskContainer)
+            } else {
+                mTaskContainers[index] = taskContainer
+            }
+        }
+        while (mTaskContainers.size > tasks.size) {
+            mTaskContainers.removeLast().apply {
+                removeView(thumbnailView)
+                taskThumbnailViewPool.recycle(thumbnailView)
+            }
+        }
+
+        setOrientationState(orientedState)
+    }
+
+    override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) {
+        cancelPendingLoadTasks()
+        if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
+            mTaskContainers.forEach {
+                if (visible) {
+                    RecentsModel.INSTANCE.get(context)
+                        .thumbnailCache
+                        .updateThumbnailInBackground(it.task) { thumbnailData: ThumbnailData ->
+                            it.thumbnailView.setThumbnail(it.task, thumbnailData)
+                        }
+                        ?.apply { pendingThumbnailRequests.add(this) }
+                } else {
+                    it.thumbnailView.setThumbnail(null, null)
+                    // Reset the task thumbnail ref
+                    it.task.thumbnail = null
+                }
+            }
+        }
+    }
+
+    // thumbnailView is laid out differently and is handled in onMeasure
+    override fun setThumbnailOrientation(orientationState: RecentsOrientedState) {}
+
+    override fun cancelPendingLoadTasks() {
+        pendingThumbnailRequests.forEach { it.cancel() }
+        pendingThumbnailRequests.clear()
+    }
+
+    override fun launchTaskAnimated(): RunnableList? {
+        val recentsView = recentsView
+        if (recentsView == null) {
+            Log.d(TAG, "launchTaskAnimated - recentsView is null")
+            return null
+        }
+
+        val endCallback = RunnableList()
+        val desktopController = recentsView.desktopRecentsController
+        if (desktopController == null) {
+            Log.d(
+                TAG,
+                "launchTaskAnimated - recentsController is null: ${taskIds.contentToString()}"
+            )
+        } else {
+            desktopController.launchDesktopFromRecents(this) { endCallback.executeAllAndDestroy() }
+            Log.d(
+                TAG,
+                "launchTaskAnimated - launchDesktopFromRecents: ${taskIds.contentToString()}"
+            )
+        }
+
+        // Callbacks get run from recentsView for case when recents animation already running
+        recentsView.addSideTaskLaunchCallback(endCallback)
+        return endCallback
+    }
+
+    override fun launchTask(callback: Consumer<Boolean>, isQuickswitch: Boolean) {
+        launchTasks()
+        callback.accept(true)
+    }
+
+    public override fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData>?) {
+        // Sets new thumbnails based on the incoming data and refreshes the rest.
+        thumbnailDatas?.let {
+            mTaskContainers.forEach {
+                val thumbnailData = thumbnailDatas[it.task.key.id]
+                if (thumbnailData != null) {
+                    it.thumbnailView.setThumbnail(it.task, thumbnailData)
+                } else {
+                    // Refresh the rest that were not updated.
+                    it.thumbnailView.refresh()
+                }
+            }
+        }
+    }
+
+    override fun onRecycle() {
+        resetPersistentViewTransforms()
+        // Clear any references to the thumbnail (it will be re-read either from the cache or the
+        // system on next bind)
+        mTaskContainers.forEach { it.thumbnailView.setThumbnail(it.task, null) }
+        setOverlayEnabled(false)
+        onTaskListVisibilityChanged(false)
+        visibility = VISIBLE
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        val containerWidth = MeasureSpec.getSize(widthMeasureSpec)
+        var containerHeight = MeasureSpec.getSize(heightMeasureSpec)
+        setMeasuredDimension(containerWidth, containerHeight)
+
+        if (mTaskContainers.isEmpty()) {
+            return
+        }
+
+        val thumbnailTopMarginPx = mContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+        containerHeight -= thumbnailTopMarginPx
+
+        BaseContainerInterface.getTaskDimension(mContext, mContainer.deviceProfile, tempPointF)
+        val windowWidth = tempPointF.x.toInt()
+        val windowHeight = tempPointF.y.toInt()
+        val scaleWidth = containerWidth / windowWidth.toFloat()
+        val scaleHeight = containerHeight / windowHeight.toFloat()
+        if (DEBUG) {
+            Log.d(
+                TAG,
+                "onMeasure: container=[$containerWidth,$containerHeight] " +
+                    "window=[$windowWidth,$windowHeight] scale=[$scaleWidth,$scaleHeight]"
+            )
+        }
+
+        // Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
+        mTaskContainers.forEach {
+            // Default to quarter of the desktop if we did not get app bounds.
+            val taskSize =
+                it.task.appBounds
+                    ?: tempRect.apply {
+                        left = 0
+                        top = 0
+                        right = windowWidth / 4
+                        bottom = windowHeight / 4
+                    }
+            val thumbWidth = (taskSize.width() * scaleWidth).toInt()
+            val thumbHeight = (taskSize.height() * scaleHeight).toInt()
+            it.thumbnailView.measure(
+                MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)
+            )
+
+            // Position the task to the same position as it would be on the desktop
+            val positionInParent = it.task.positionInParent ?: ORIGIN
+            val taskX = (positionInParent.x * scaleWidth).toInt()
+            var taskY = (positionInParent.y * scaleHeight).toInt()
+            // move task down by margin size
+            taskY += thumbnailTopMarginPx
+            it.thumbnailView.x = taskX.toFloat()
+            it.thumbnailView.y = taskY.toFloat()
+            if (DEBUG) {
+                Log.d(
+                    TAG,
+                    "onMeasure: task=${it.task.key} thumb=[$thumbWidth,$thumbHeight]" +
+                        " pos=[$taskX,$taskY]"
+                )
+            }
+        }
+    }
+
+    // TODO(b/330685808) support overlay for Screenshot action
+    override fun setOverlayEnabled(overlayEnabled: Boolean) {}
+
+    override fun setFullscreenProgress(progress: Float) {
+        // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
+        val boundProgress = Utilities.boundToRange(progress, 0f, 1f)
+        mFullscreenProgress = boundProgress
+        mIconView.setVisibility(if (boundProgress < 1) VISIBLE else INVISIBLE)
+        // Don't show background while we are transitioning to/from fullscreen
+        backgroundView.visibility = if (mFullscreenProgress > 0) INVISIBLE else VISIBLE
+        mTaskContainers.forEach {
+            it.thumbnailView.taskOverlay.setFullscreenProgress(boundProgress)
+        }
+        // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
+        // oversized and banner would look disproportionately large.
+        if (
+            mContainer.getOverviewPanel<RecentsView<*, *>>().getStateManager().state !=
+                LauncherState.BACKGROUND_APP
+        ) {
+            setIconsAndBannersTransitionProgress(boundProgress, true)
+        }
+        updateSnapshotRadius()
+    }
+
+    override fun updateSnapshotRadius() {
+        super.updateSnapshotRadius()
+        updateFullscreenParams(snapshotDrawParams)
+        mTaskContainers.forEach { it.thumbnailView.setFullscreenParams(snapshotDrawParams) }
+    }
+
+    override fun setColorTint(amount: Float, tintColor: Int) {
+        mTaskContainers.forEach { it.thumbnailView.dimAlpha = amount }
+    }
+
+    override fun applyThumbnailSplashAlpha() {
+        mTaskContainers.forEach { it.thumbnailView.setSplashAlpha(mTaskThumbnailSplashAlpha) }
+    }
+
+    public override fun setThumbnailVisibility(visibility: Int, taskId: Int) {
+        mTaskContainers.forEach { it.thumbnailView.visibility = visibility }
+    }
+
+    // Desktop tile can't be in split screen
+    override fun confirmSecondSplitSelectApp(): Boolean = false
+
+    companion object {
+        private const val TAG = "DesktopTaskView"
+        private const val DEBUG = true
+        private val ORIGIN = Point(0, 0)
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 8fa5375..4df9414 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -19,7 +19,7 @@
 import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
 
 import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
+import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
 
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
@@ -79,7 +79,7 @@
     static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
     static final int MINUTE_MS = 60000;
 
-    private static final String TAG = DigitalWellBeingToast.class.getSimpleName();
+    private static final String TAG = "DigitalWellBeingToast";
 
     private final RecentsViewContainer mContainer;
     private final TaskView mTaskView;
@@ -140,7 +140,7 @@
     public void initialize(Task task) {
         mAppUsageLimitTimeMs = mAppRemainingTimeMs = -1;
         mTask = task;
-        THREAD_POOL_EXECUTOR.execute(() -> {
+        ORDERED_BG_EXECUTOR.execute(() -> {
                     AppUsageLimit usageLimit = null;
                     try {
                         usageLimit = mLauncherApps.getAppUsageLimit(
@@ -320,12 +320,12 @@
                 (FrameLayout.LayoutParams) mBanner.getLayoutParams();
         DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
-                mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
+                mTaskView.getFirstThumbnailView().getLayoutParams()).bottomMargin;
         RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
         Pair<Float, Float> translations = orientationHandler
                 .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
                         mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
-                        mTaskView.getThumbnails(), mTask.key.id, mBanner);
+                        mTaskView.getThumbnailViews(), mTask.key.id, mBanner);
         mSplitOffsetTranslationX = translations.first;
         mSplitOffsetTranslationY = translations.second;
         updateTranslationY();
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
index 0d49309..e024995 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
@@ -36,17 +36,18 @@
  * animation. Consists of a rectangular background that splits into two, and two app icons that
  * increase in size during the animation.
  */
-class FloatingAppPairBackground(
-    context: Context,
-    private val floatingView: FloatingAppPairView, // the view that we will draw this background on
-    private val appIcon1: Drawable,
-    private val appIcon2: Drawable,
-    dividerPos: Int
+open class FloatingAppPairBackground(
+        context: Context,
+        // the view that we will draw this background on
+        protected val floatingView: FloatingAppPairView,
+        private val appIcon1: Drawable,
+        private val appIcon2: Drawable?,
+        dividerPos: Int
 ) : Drawable() {
     companion object {
         // Design specs -- app icons start small and expand during the animation
-        private val STARTING_ICON_SIZE_PX = Utilities.dpToPx(22f)
-        private val ENDING_ICON_SIZE_PX = Utilities.dpToPx(66f)
+        internal val STARTING_ICON_SIZE_PX = Utilities.dpToPx(22f)
+        internal val ENDING_ICON_SIZE_PX = Utilities.dpToPx(66f)
 
         // Null values to use with drawDoubleRoundRect(), since there doesn't seem to be any other
         // API for drawing rectangles with 4 different corner radii.
@@ -58,13 +59,13 @@
     private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
 
     // Animation interpolators
-    private val expandXInterpolator: Interpolator
-    private val expandYInterpolator: Interpolator
+    protected val expandXInterpolator: Interpolator
+    protected val expandYInterpolator: Interpolator
     private val cellSplitInterpolator: Interpolator
-    private val iconFadeInterpolator: Interpolator
+    protected val iconFadeInterpolator: Interpolator
 
     // Device-specific measurements
-    private val deviceCornerRadius: Float
+    protected val deviceCornerRadius: Float
     private val deviceHalfDividerSize: Float
     private val desiredSplitRatio: Float
 
@@ -214,7 +215,7 @@
         canvas.save()
         canvas.translate(changingIcon2Left, changingIconTop)
         canvas.scale(changingIconScaleX, changingIconScaleY)
-        appIcon2.alpha = changingIconAlpha
+        appIcon2!!.alpha = changingIconAlpha
         appIcon2.draw(canvas)
         canvas.restore()
     }
@@ -312,7 +313,7 @@
         canvas.save()
         canvas.translate(changingIconLeft, changingIcon2Top)
         canvas.scale(changingIconScaleX, changingIconScaleY)
-        appIcon2.alpha = changingIconAlpha
+        appIcon2!!.alpha = changingIconAlpha
         appIcon2.draw(canvas)
         canvas.restore()
     }
@@ -325,7 +326,7 @@
      * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top
      *   right y, bottom right x, and so on.
      */
-    private fun drawCustomRoundedRect(c: Canvas, rect: RectF, radii: FloatArray) {
+    protected fun drawCustomRoundedRect(c: Canvas, rect: RectF, radii: FloatArray) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
             // Canvas.drawDoubleRoundRect is supported from Q onward
             c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, backgroundPaint)
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
index e90aa13..e8d1cc1 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
@@ -40,8 +40,8 @@
         fun getFloatingAppPairView(
             launcher: StatefulActivity<*>,
             originalView: View,
-            appIcon1: Drawable,
-            appIcon2: Drawable,
+            appIcon1: Drawable?,
+            appIcon2: Drawable?,
             dividerPos: Int
         ): FloatingAppPairView {
             val dragLayer: ViewGroup = launcher.getDragLayer()
@@ -64,8 +64,8 @@
     fun init(
         launcher: StatefulActivity<*>,
         originalView: View,
-        appIcon1: Drawable,
-        appIcon2: Drawable,
+        appIcon1: Drawable?,
+        appIcon2: Drawable?,
         dividerPos: Int
     ) {
         val viewBounds = Rect(0, 0, originalView.width, originalView.height)
@@ -92,7 +92,14 @@
         layoutParams = lp
 
         // Prepare to draw app pair icon background
-        background = FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
+        background = if (appIcon1 == null || appIcon2 == null) {
+            val iconToAnimate = appIcon1 ?: appIcon2
+            checkNotNull(iconToAnimate)
+            FloatingFullscreenAppPairBackground(context, this, iconToAnimate,
+                    dividerPos)
+        } else {
+            FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
+        }
         background.setBounds(0, 0, lp.width, lp.height)
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt
new file mode 100644
index 0000000..8cd997f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+
+class FloatingFullscreenAppPairBackground(
+        context: Context,
+        floatingView: FloatingAppPairView,
+        private val iconToLaunch: Drawable,
+        dividerPos: Int) :
+        FloatingAppPairBackground(
+                context,
+                floatingView,
+                iconToLaunch,
+                null /*appIcon2*/,
+                dividerPos
+) {
+
+    /** Animates the background as if launching a fullscreen task. */
+    override fun draw(canvas: Canvas) {
+        val progress = floatingView.progress
+
+        // Since the entire floating app pair surface is scaling up during this animation, we
+        // scale down most of these drawn elements so that they appear the proper size on-screen.
+        val scaleFactorX = floatingView.scaleX
+        val scaleFactorY = floatingView.scaleY
+
+        // Get the bounds where we will draw the background image
+        val width = bounds.width().toFloat()
+        val height = bounds.height().toFloat()
+
+        // Get device-specific measurements
+        val cornerRadiusX = deviceCornerRadius / scaleFactorX
+        val cornerRadiusY = deviceCornerRadius / scaleFactorY
+
+        // Draw background
+        drawCustomRoundedRect(
+                canvas,
+                RectF(0f, 0f, width, height),
+                floatArrayOf(
+                        cornerRadiusX,
+                        cornerRadiusY,
+                        cornerRadiusX,
+                        cornerRadiusY,
+                        cornerRadiusX,
+                        cornerRadiusY,
+                        cornerRadiusX,
+                        cornerRadiusY,
+                )
+        )
+
+        // Calculate changing measurements for icon.
+        val changingIconSizeX =
+                (STARTING_ICON_SIZE_PX +
+                        ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                                expandXInterpolator.getInterpolation(progress))) / scaleFactorX
+        val changingIconSizeY =
+                (STARTING_ICON_SIZE_PX +
+                        ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                                expandYInterpolator.getInterpolation(progress))) / scaleFactorY
+
+        val changingIcon1Left = (width / 2f) - (changingIconSizeX / 2f)
+        val changingIconTop = (height / 2f) - (changingIconSizeY / 2f)
+        val changingIconScaleX = changingIconSizeX / iconToLaunch.bounds.width()
+        val changingIconScaleY = changingIconSizeY / iconToLaunch.bounds.height()
+        val changingIconAlpha =
+                (255 - (255 * iconFadeInterpolator.getInterpolation(progress))).toInt()
+
+        // Draw icon
+        canvas.save()
+        canvas.translate(changingIcon1Left, changingIconTop)
+        canvas.scale(changingIconScaleX, changingIconScaleY)
+        iconToLaunch.alpha = changingIconAlpha
+        iconToLaunch.draw(canvas)
+        canvas.restore()
+    }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
index d869fed..e5a7333 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
@@ -31,7 +31,7 @@
 /**
  * A child view of {@link com.android.quickstep.views.FloatingTaskView} to draw the thumbnail in a
  * rounded corner frame. While the purpose of this class sounds similar to
- * {@link TaskThumbnailView}, it doesn't need a lot of complex logic in {@link TaskThumbnailView}
+ * {@link TaskThumbnailViewDeprecated}, it doesn't need a lot of complex logic in {@link TaskThumbnailViewDeprecated}
  * in relation to moving with {@link RecentsView}.
  */
 public class FloatingTaskThumbnailView extends View {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 9e1c856..1ccb764 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -6,11 +6,13 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
@@ -30,6 +32,7 @@
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.TransformingTouchDelegate;
+import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskIconCache;
 import com.android.quickstep.TaskThumbnailCache;
@@ -43,7 +46,9 @@
 
 import kotlin.Unit;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Optional;
 import java.util.function.Consumer;
 
 /**
@@ -58,9 +63,9 @@
  */
 public class GroupedTaskView extends TaskView {
 
-    @Nullable
-    private Task mSecondaryTask;
-    private TaskThumbnailView mSnapshotView2;
+    private static final String TAG = "GroupedTaskView";
+    // TODO(b/336612373): Support new TTV for GroupedTaskView
+    private TaskThumbnailViewDeprecated mSnapshotView2;
     private TaskViewIcon mIconView2;
     @Nullable
     private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
@@ -68,7 +73,8 @@
     private CancellableTask mIconLoadRequest2;
     private final float[] mIcon2CenterCoords = new float[2];
     private TransformingTouchDelegate mIcon2TouchDelegate;
-    @Nullable private SplitBounds mSplitBoundsConfig;
+    @Nullable
+    private SplitBounds mSplitBoundsConfig;
     private final DigitalWellBeingToast mDigitalWellBeingToast2;
 
     public GroupedTaskView(Context context) {
@@ -84,24 +90,49 @@
         mDigitalWellBeingToast2 = new DigitalWellBeingToast(mContainer, this);
     }
 
+    /**
+     * Returns the second task bound to this TaskView.
+     *
+     * @deprecated Use {@link #mTaskContainers} instead.
+     */
+    @Deprecated
+    @Nullable
+    private Task getSecondTask() {
+        return mTaskContainers.size() > 1 ? mTaskContainers.get(1).getTask() : null;
+    }
+
     @Override
-    protected Unit updateBorderBounds(@NonNull Rect bounds) {
+    public Unit getThumbnailBounds(@NonNull Rect bounds, boolean relativeToDragLayer) {
         if (mSplitBoundsConfig == null) {
-            super.updateBorderBounds(bounds);
+            super.getThumbnailBounds(bounds, relativeToDragLayer);
             return Unit.INSTANCE;
         }
-        bounds.set(
-                Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
-                        mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
-                Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
-                        mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
-                Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
-                        mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
-                Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
-                        mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
+        if (relativeToDragLayer) {
+            Rect firstThumbnailBounds = new Rect();
+            Rect secondThumbnailBounds = new Rect();
+            BaseDragLayer dragLayer = mContainer.getDragLayer();
+            dragLayer.getDescendantRectRelativeToSelf(
+                    mTaskThumbnailViewDeprecated, firstThumbnailBounds);
+            dragLayer.getDescendantRectRelativeToSelf(mSnapshotView2, secondThumbnailBounds);
+
+            bounds.set(firstThumbnailBounds);
+            bounds.union(secondThumbnailBounds);
+        } else {
+            bounds.set(getSnapshotViewBounds(mTaskThumbnailViewDeprecated));
+            bounds.union(getSnapshotViewBounds(mSnapshotView2));
+        }
         return Unit.INSTANCE;
     }
 
+    private Rect getSnapshotViewBounds(@NonNull View snapshotView) {
+        int snapshotViewX = Math.round(snapshotView.getX());
+        int snapshotViewY = Math.round(snapshotView.getY());
+        return new Rect(snapshotViewX,
+                snapshotViewY,
+                snapshotViewX + snapshotView.getWidth(),
+                snapshotViewY + snapshotView.getHeight());
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -119,18 +150,18 @@
     public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
             @Nullable SplitBounds splitBoundsConfig) {
         super.bind(primary, orientedState);
-        mSecondaryTask = secondary;
-        mTaskIdContainer[1] = secondary.key.id;
-        mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2,
-                mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT);
-        mTaskIdAttributeContainer[0].setStagePosition(
+        mTaskContainers = Arrays.asList(
+                mTaskContainers.get(0),
+                new TaskContainer(secondary, findViewById(R.id.bottomright_snapshot),
+                        mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT, mDigitalWellBeingToast2));
+        mTaskContainers.get(0).setStagePosition(
                 SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
         mSnapshotView2.bind(secondary);
         mSplitBoundsConfig = splitBoundsConfig;
         if (mSplitBoundsConfig == null) {
             return;
         }
-        mSnapshotView.getPreviewPositionHelper().setSplitBounds(
+        mTaskThumbnailViewDeprecated.getPreviewPositionHelper().setSplitBounds(
                 convertLauncherSplitBoundsToShell(splitBoundsConfig),
                 PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
         mSnapshotView2.getPreviewPositionHelper().setSplitBounds(
@@ -145,9 +176,12 @@
     public void setUpShowAllInstancesListener() {
         // sets up the listener for the left/top task
         super.setUpShowAllInstancesListener();
+        if (mTaskContainers.size() < 2) {
+            return;
+        }
 
         // right/bottom task's base package name
-        String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName();
+        String taskPackageName = mTaskContainers.get(1).getTask().key.getPackageName();
 
         // icon of the right/bottom task
         View showWindowsView = findViewById(R.id.show_windows_right);
@@ -163,20 +197,21 @@
             TaskIconCache iconCache = model.getIconCache();
 
             if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
-                mThumbnailLoadRequest2 = thumbnailCache.updateThumbnailInBackground(mSecondaryTask,
-                        thumbnailData -> mSnapshotView2.setThumbnail(
-                                mSecondaryTask, thumbnailData
+                mThumbnailLoadRequest2 = thumbnailCache.updateThumbnailInBackground(
+                        getSecondTask(),
+                        thumbnailData -> mSnapshotView2.setThumbnail(getSecondTask(),
+                                thumbnailData
                         ));
             }
 
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
-                mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
+                mIconLoadRequest2 = iconCache.updateIconInBackground(getSecondTask(),
                         (task) -> {
                             setIcon(mIconView2, task.icon);
                             if (enableOverviewIconMenu()) {
                                 setText(mIconView2, task.title);
                             }
-                            mDigitalWellBeingToast2.initialize(mSecondaryTask);
+                            mDigitalWellBeingToast2.initialize(getSecondTask());
                             mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
                             mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
                         });
@@ -186,7 +221,7 @@
                 mSnapshotView2.setThumbnail(null, null);
                 // Reset the task thumbnail reference as well (it will be fetched from the cache or
                 // reloaded next time we need it)
-                mSecondaryTask.thumbnail = null;
+                getSecondTask().thumbnail = null;
             }
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                 setIcon(mIconView2, null);
@@ -244,7 +279,7 @@
     @Nullable
     @Override
     public RunnableList launchTaskAnimated() {
-        if (mTask == null || mSecondaryTask == null) {
+        if (mTaskContainers.isEmpty()) {
             return null;
         }
 
@@ -258,7 +293,6 @@
             InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
         }, false /* freezeTaskList */, true /*launchingExistingTaskview*/);
 
-
         // Callbacks get run from recentsView for case when recents animation already running
         recentsView.addSideTaskLaunchCallback(endCallback);
         return endCallback;
@@ -278,18 +312,20 @@
     private void launchTaskInternal(@NonNull Consumer<Boolean> callback, boolean isQuickswitch,
             boolean launchingExistingTaskView) {
         getRecentsView().getSplitSelectController().launchExistingSplitPair(
-                launchingExistingTaskView ? this : null, mTask.key.id,
-                mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+                launchingExistingTaskView ? this : null, getFirstTask().key.id,
+                getSecondTask().key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
                 callback, isQuickswitch, getSnapPosition());
+        Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: " + Arrays.toString(
+                getTaskIds()));
     }
 
     @Override
     void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
         super.refreshThumbnails(thumbnailDatas);
-        if (mSecondaryTask != null && thumbnailDatas != null) {
-            final ThumbnailData thumbnailData = thumbnailDatas.get(mSecondaryTask.key.id);
+        if (getSecondTask() != null && thumbnailDatas != null) {
+            final ThumbnailData thumbnailData = thumbnailDatas.get(getSecondTask().key.id);
             if (thumbnailData != null) {
-                mSnapshotView2.setThumbnail(mSecondaryTask, thumbnailData);
+                mSnapshotView2.setThumbnail(getSecondTask(), thumbnailData);
                 return;
             }
         }
@@ -297,15 +333,14 @@
         mSnapshotView2.refresh();
     }
 
-    @Override
-    public boolean containsTaskId(int taskId) {
-        return (mTask != null && mTask.key.id == taskId)
-                || (mSecondaryTask != null && mSecondaryTask.key.id == taskId);
-    }
-
-    @Override
-    public TaskThumbnailView[] getThumbnails() {
-        return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2};
+    /**
+     * Returns taskId that split selection was initiated with,
+     * {@link ActivityTaskManager#INVALID_TASK_ID} if no tasks in this TaskView are part of
+     * split selection
+     */
+    protected int getThisTaskCurrentlyInSplitSelection() {
+        int initialTaskId = getRecentsView().getSplitSelectController().getInitialTaskId();
+        return containsTaskId(initialTaskId) ? initialTaskId : INVALID_TASK_ID;
     }
 
     @Override
@@ -318,7 +353,7 @@
             // below aren't reliable since both of those views may be gone/transformed
             int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
             if (initSplitTaskId != INVALID_TASK_ID) {
-                return initSplitTaskId == mTask.key.id ? 1 : 0;
+                return initSplitTaskId == getFirstTask().key.id ? 1 : 0;
             }
         }
 
@@ -339,7 +374,7 @@
     @Override
     public void onRecycle() {
         super.onRecycle();
-        mSnapshotView2.setThumbnail(mSecondaryTask, null);
+        mSnapshotView2.setThumbnail(getSecondTask(), null);
         mSplitBoundsConfig = null;
     }
 
@@ -349,32 +384,37 @@
         int widthSize = MeasureSpec.getSize(widthMeasureSpec);
         int heightSize = MeasureSpec.getSize(heightMeasureSpec);
         setMeasuredDimension(widthSize, heightSize);
-        if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
+        if (mSplitBoundsConfig == null || mTaskThumbnailViewDeprecated == null
+                || mSnapshotView2 == null) {
             return;
         }
         int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
         if (initSplitTaskId == INVALID_TASK_ID) {
-            getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
+            getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(
+                    mTaskThumbnailViewDeprecated,
                     mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
                     mContainer.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
             // Should we be having a separate translation step apart from the measuring above?
             // The following only applies to large screen for now, but for future reference
             // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
             // translation directions
-            mSnapshotView.applySplitSelectTranslateX(mSnapshotView.getTranslationX());
-            mSnapshotView.applySplitSelectTranslateY(mSnapshotView.getTranslationY());
+            mTaskThumbnailViewDeprecated.applySplitSelectTranslateX(
+                    mTaskThumbnailViewDeprecated.getTranslationX());
+            mTaskThumbnailViewDeprecated.applySplitSelectTranslateY(
+                    mTaskThumbnailViewDeprecated.getTranslationY());
             mSnapshotView2.applySplitSelectTranslateX(mSnapshotView2.getTranslationX());
             mSnapshotView2.applySplitSelectTranslateY(mSnapshotView2.getTranslationY());
         } else {
             // Currently being split with this taskView, let the non-split selected thumbnail
             // take up full thumbnail area
-            TaskIdAttributeContainer container =
-                    mTaskIdAttributeContainer[initSplitTaskId == mTask.key.id ? 1 : 0];
-            container.getThumbnailView().measure(widthMeasureSpec,
-                    View.MeasureSpec.makeMeasureSpec(
-                            heightSize -
-                                    mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx,
-                            MeasureSpec.EXACTLY));
+            Optional<TaskContainer> nonSplitContainer = mTaskContainers.stream().filter(
+                    container -> container.getTask().key.id != initSplitTaskId).findAny();
+            nonSplitContainer.ifPresent(
+                    taskIdAttributeContainer -> taskIdAttributeContainer.getThumbnailView().measure(
+                            widthMeasureSpec, MeasureSpec.makeMeasureSpec(
+                                    heightSize - mContainer.getDeviceProfile()
+                                            .overviewTaskThumbnailTopMarginPx,
+                                    MeasureSpec.EXACTLY)));
         }
         if (!enableOverviewIconMenu()) {
             updateIconPlacement();
@@ -446,17 +486,18 @@
                     mSplitBoundsConfig);
         } else {
             getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
-                    taskIconHeight, mSnapshotView.getMeasuredWidth(),
-                    mSnapshotView.getMeasuredHeight(), getMeasuredHeight(), getMeasuredWidth(),
+                    taskIconHeight, mTaskThumbnailViewDeprecated.getMeasuredWidth(),
+                    mTaskThumbnailViewDeprecated.getMeasuredHeight(), getMeasuredHeight(),
+                    getMeasuredWidth(),
                     isRtl, deviceProfile, mSplitBoundsConfig);
         }
     }
 
     private void updateSecondaryDwbPlacement() {
-        if (mSecondaryTask == null) {
+        if (getSecondTask() == null) {
             return;
         }
-        mDigitalWellBeingToast2.initialize(mSecondaryTask);
+        mDigitalWellBeingToast2.initialize(getSecondTask());
     }
 
     @Override
@@ -509,17 +550,11 @@
      */
     @Override
     void setThumbnailVisibility(int visibility, int taskId) {
-        if (visibility == VISIBLE) {
-            mSnapshotView.setVisibility(visibility);
-            mDigitalWellBeingToast.setBannerVisibility(visibility);
-            mSnapshotView2.setVisibility(visibility);
-            mDigitalWellBeingToast2.setBannerVisibility(visibility);
-        } else if (taskId == getTaskIds()[0]) {
-            mSnapshotView.setVisibility(visibility);
-            mDigitalWellBeingToast.setBannerVisibility(visibility);
-        } else {
-            mSnapshotView2.setVisibility(visibility);
-            mDigitalWellBeingToast2.setBannerVisibility(visibility);
+        for (TaskContainer container : mTaskContainers) {
+            if (visibility == VISIBLE || container.getTask().key.id == taskId) {
+                container.getThumbnailView().setVisibility(visibility);
+                container.getDigitalWellBeingToast().setBannerVisibility(visibility);
+            }
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 06c2aa3..8d1907f 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -260,7 +261,8 @@
         super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
         DesktopVisibilityController desktopVisibilityController =
                 mContainer.getDesktopVisibilityController();
-        if (desktopVisibilityController != null) {
+        if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+            // TODO: b/333533253 - Remove after flag rollout
             desktopVisibilityController.setRecentsGestureStart();
         }
     }
@@ -282,7 +284,8 @@
             }
         }
         super.onGestureAnimationEnd();
-        if (desktopVisibilityController != null) {
+        if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+            // TODO: b/333533253 - Remove after flag rollout
             desktopVisibilityController.setRecentsGestureEnd(endTarget);
         }
         if (showDesktopApps) {
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 5188d4a..ba60141 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -33,22 +34,35 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
+import com.android.quickstep.util.AppPairsController;
 import com.android.quickstep.util.LayoutUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.function.Consumer;
 
 /**
  * View for showing action buttons in Overview
  */
 public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
         implements OnClickListener, Insettable {
+    public static final FloatProperty<Consumer<Float>> FLOAT_SETTER =
+            new FloatProperty<>("floatSetter") {
+                @Override
+                public void setValue(Consumer<Float> consumer, float v) {
+                    consumer.accept(v);
+                }
+
+                @Override
+                public Float get(Consumer<Float> consumer) {
+                    return -1f;
+                }
+            };
 
     private final Rect mInsets = new Rect();
 
@@ -89,30 +103,24 @@
     private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
     private static final int INDEX_SHARE_TARGET_ALPHA = 4;
     private static final int INDEX_SCROLL_ALPHA = 5;
-    private static final int NUM_ALPHAS = 6;
-
-    public @interface ScreenshotButtonHiddenFlags { }
-    public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
+    private static final int INDEX_GROUPED_ALPHA = 6;
+    private static final int INDEX_3P_LAUNCHER = 7;
+    private static final int NUM_ALPHAS = 8;
 
     public @interface SplitButtonHiddenFlags { }
     public static final int FLAG_SMALL_SCREEN_HIDE_SPLIT = 1 << 0;
-    public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
 
-    public @interface SplitButtonDisabledFlags { }
-    public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
+    /** Holds MultiValueAlpha values for all actions buttons */
+    private final MultiValueAlpha[] mMultiValueAlphas = new MultiValueAlpha[2];
+    /** Index used for single-task actions in the mMultiValueAlphas array */
+    private static final int ACTIONS_ALPHAS = 0;
+    /** Index used for grouped-task actions in the mMultiValueAlphas array */
+    private static final int GROUP_ACTIONS_ALPHAS = 1;
 
-    public @interface AppPairButtonHiddenFlags { }
-    public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
-    public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
-    public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
-
-    private MultiValueAlpha mMultiValueAlpha;
-
+    /** Container for the action buttons below a focused, non-split Overview tile. */
     protected LinearLayout mActionButtons;
-    // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
-    // ImageButton in go launcher (does not share a common class with Button). Take care when
-    // casting this.
-    private View mScreenshotButton;
+    /** Container for the action buttons below a focused, split Overview tile. */
+    protected LinearLayout mGroupActionButtons;
     private Button mSplitButton;
     private Button mSaveAppPairButton;
 
@@ -122,21 +130,17 @@
     @ActionsDisabledFlags
     protected int mDisabledFlags;
 
-    @ScreenshotButtonHiddenFlags
-    private int mScreenshotButtonHiddenFlags;
-
     @SplitButtonHiddenFlags
     private int mSplitButtonHiddenFlags;
 
-    @AppPairButtonHiddenFlags
-    private int mAppPairButtonHiddenFlags;
-
     @Nullable
     protected T mCallbacks;
 
     @Nullable
     protected DeviceProfile mDp;
     private final Rect mTaskSize = new Rect();
+    private boolean mIsGroupedTask = false;
+    private boolean mCanSaveAppPair = false;
 
     public OverviewActionsView(Context context) {
         this(context, null);
@@ -153,12 +157,21 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        // Initialize 2 view containers: one for single tasks, one for grouped tasks.
+        // These will take up the same space on the screen and alternate visibility as needed.
         mActionButtons = findViewById(R.id.action_buttons);
-        mMultiValueAlpha = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
-        mMultiValueAlpha.setUpdateVisibility(true);
+        mGroupActionButtons = findViewById(R.id.group_action_buttons);
+        // Initialize a list to set alpha on mActionButtons and mGroupActionButtons simultaneously.
+        mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
+        mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
+                new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+        Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
 
-        mScreenshotButton = findViewById(R.id.action_screenshot);
-        mScreenshotButton.setOnClickListener(this);
+        // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is
+        // an ImageButton in go launcher (does not share a common class with Button). Take care when
+        // casting this.
+        View screenshotButton = findViewById(R.id.action_screenshot);
+        screenshotButton.setOnClickListener(this);
         mSplitButton = findViewById(R.id.action_split);
         mSplitButton.setOnClickListener(this);
         mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
@@ -209,7 +222,7 @@
             mHiddenFlags &= ~visibilityFlags;
         }
         boolean isHidden = mHiddenFlags != 0;
-        mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
+        setActionsAlpha(INDEX_HIDDEN_FLAGS_ALPHA, isHidden ? 0 : 1);
     }
 
     /**
@@ -234,14 +247,13 @@
      * Updates a batch of flags to hide and show actions buttons when a grouped task (split screen)
      * is focused.
      * @param isGroupedTask True if the focused task is a grouped task.
+     * @param canSaveAppPair True if the focused task is a grouped task and can be saved as an app
+     *                      pair.
      */
-    public void updateForGroupedTask(boolean isGroupedTask) {
-        // Update flags to see if split button should be hidden.
-        updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
-        // Update flags to see if screenshot button should be hidden.
-        updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
-        // Update flags to see if save app pair button should be hidden.
-        updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
+    public void updateForGroupedTask(boolean isGroupedTask, boolean canSaveAppPair) {
+        mIsGroupedTask = isGroupedTask;
+        mCanSaveAppPair = canSaveAppPair;
+        updateActionButtonsVisibility();
     }
 
     /**
@@ -251,36 +263,30 @@
         assert mDp != null;
         // Update flags to see if split button should be hidden.
         updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet);
-        // Update flags to see if save app pair button should be hidden.
-        updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet);
+        updateActionButtonsVisibility();
+    }
+
+    private void updateActionButtonsVisibility() {
+        assert mDp != null;
+        boolean showSingleTaskActions = !mIsGroupedTask;
+        boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
+        getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
+        getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
     }
 
     /**
      * Updates flags to hide and show actions buttons for 1p/3p launchers.
      */
     public void updateFor3pLauncher(boolean is3pLauncher) {
-        updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
+        getGroupActionsAlphas().get(INDEX_3P_LAUNCHER).setValue(is3pLauncher ? 0 : 1);
     }
 
-    /**
-     * Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
-     *
-     * @param flag   The flag to update.
-     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
-     */
-    private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
-            boolean enable) {
-        if (mScreenshotButton == null) return;
-        if (enable) {
-            mScreenshotButtonHiddenFlags |= flag;
-        } else {
-            mScreenshotButtonHiddenFlags &= ~flag;
-        }
-        int desiredVisibility = mScreenshotButtonHiddenFlags == 0 ? VISIBLE : GONE;
-        if (mScreenshotButton.getVisibility() != desiredVisibility) {
-            mScreenshotButton.setVisibility(desiredVisibility);
-            mActionButtons.requestLayout();
-        }
+    private MultiValueAlpha getActionsAlphas() {
+        return mMultiValueAlphas[ACTIONS_ALPHAS];
+    }
+
+    private MultiValueAlpha getGroupActionsAlphas() {
+        return mMultiValueAlphas[GROUP_ACTIONS_ALPHAS];
     }
 
     /**
@@ -304,56 +310,36 @@
         }
     }
 
-    /**
-     * Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
-     *
-     * @param flag   The flag to update.
-     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
-     */
-    private void updateAppPairButtonHiddenFlags(
-            @AppPairButtonHiddenFlags int flag, boolean enable) {
-        if (!FeatureFlags.enableAppPairs()) {
-            return;
-        }
-
-        if (mSaveAppPairButton == null) return;
-        if (enable) {
-            mAppPairButtonHiddenFlags |= flag;
-        } else {
-            mAppPairButtonHiddenFlags &= ~flag;
-        }
-        int desiredVisibility = mAppPairButtonHiddenFlags == 0 ? VISIBLE : GONE;
-        if (mSaveAppPairButton.getVisibility() != desiredVisibility) {
-            mSaveAppPairButton.setVisibility(desiredVisibility);
-            mActionButtons.requestLayout();
-        }
+    private void setActionsAlpha(int index, float value) {
+        Arrays.stream(mMultiValueAlphas).forEach(a -> a.get(index).setValue(value));
     }
 
-    public MultiProperty getContentAlpha() {
-        return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA);
+    public Consumer<Float> getContentAlphaSetter() {
+        return v -> setActionsAlpha(INDEX_CONTENT_ALPHA, v);
     }
 
-    public MultiProperty getVisibilityAlpha() {
-        return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA);
+    public Consumer<Float> getVisibilityAlphaSetter() {
+        return v -> setActionsAlpha(INDEX_VISIBILITY_ALPHA, v);
     }
 
-    public MultiProperty getFullscreenAlpha() {
-        return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA);
+    public Consumer<Float> getFullscreenAlphaSetter() {
+        return v -> setActionsAlpha(INDEX_FULLSCREEN_ALPHA, v);
     }
 
-    public MultiProperty getShareTargetAlpha() {
-        return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA);
+    public Consumer<Float> getShareTargetAlphaSetter() {
+        return v -> setActionsAlpha(INDEX_SHARE_TARGET_ALPHA, v);
     }
 
-    public MultiProperty getIndexScrollAlpha() {
-        return mMultiValueAlpha.get(INDEX_SCROLL_ALPHA);
+    public Consumer<Float> getIndexScrollAlphaSetter() {
+        return v -> setActionsAlpha(INDEX_SCROLL_ALPHA, v);
     }
 
     /**
      * Returns the visibility of the overview actions buttons.
      */
-    public @Visibility int getActionsButtonVisibility() {
-        return mActionButtons.getVisibility();
+    public boolean areActionsButtonsVisible() {
+        return mActionButtons.getVisibility() == View.VISIBLE
+                || mGroupActionButtons.getVisibility() == View.VISIBLE;
     }
 
     /**
@@ -366,10 +352,17 @@
 
     /** Updates vertical margins for different navigation mode or configuration changes. */
     public void updateVerticalMargin(NavigationMode mode) {
+        updateActionBarPosition(mActionButtons);
+        updateActionBarPosition(mGroupActionButtons);
+    }
+
+    /** Positions actions buttons according to device settings and insets. */
+    private void updateActionBarPosition(LinearLayout actionBar) {
         if (mDp == null) {
             return;
         }
-        LayoutParams actionParams = (LayoutParams) mActionButtons.getLayoutParams();
+
+        LayoutParams actionParams = (LayoutParams) actionBar.getLayoutParams();
         actionParams.setMargins(
                 actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
                 actionParams.rightMargin, getBottomMargin());
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 791ef04..a242e1d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -35,6 +35,7 @@
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
+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.LauncherState.BACKGROUND_APP;
@@ -68,7 +69,6 @@
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SCREEN;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SELECT_ACTIVE;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -131,6 +131,7 @@
 import com.android.internal.jank.Cuj;
 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;
@@ -167,6 +168,7 @@
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.BaseContainerInterface;
+import com.android.quickstep.DesktopModeStatus;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.RecentsAnimationController;
@@ -185,6 +187,7 @@
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.ViewUtils;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.recents.viewmodel.RecentsViewData;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AnimUtils;
@@ -203,7 +206,7 @@
 import com.android.quickstep.util.TaskVisualsChangeListener;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.util.VibrationConstants;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.plugins.ResourceProvider;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -375,6 +378,9 @@
                 public void setValue(RecentsView view, float scale) {
                     view.setScaleX(scale);
                     view.setScaleY(scale);
+                    if (enableRefactorTaskThumbnail()) {
+                        view.mRecentsViewData.getScale().setValue(scale);
+                    }
                     view.mLastComputedTaskStartPushOutDistance = null;
                     view.mLastComputedTaskEndPushOutDistance = null;
                     view.runActionOnRemoteHandles(new Consumer<RemoteTargetHandle>() {
@@ -445,6 +451,8 @@
 
     private static final float FOREGROUND_SCRIM_TINT = 0.32f;
 
+    public final RecentsViewData mRecentsViewData = new RecentsViewData();
+
     protected final RecentsOrientedState mOrientationState;
     protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
     @Nullable
@@ -590,7 +598,7 @@
             if (taskView == null) {
                 return;
             }
-            Task.TaskKey taskKey = taskView.getTask().key;
+            Task.TaskKey taskKey = taskView.getFirstTask().key;
             UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
                     () -> PackageManagerWrapper.getInstance()
                             .getActivityInfo(taskKey.getComponent(), taskKey.userId) == null,
@@ -625,7 +633,6 @@
      */
     protected int mRunningTaskViewId = -1;
     private int mTaskViewIdCount;
-    private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
     protected boolean mRunningTaskTileHidden;
     @Nullable
     private Task[] mTmpRunningTasks;
@@ -770,6 +777,8 @@
     // keeps track of the state of the filter for tasks in recents view
     private final RecentsFilterState mFilterState = new RecentsFilterState();
 
+    private int mOffsetMidpointIndexOverride = INVALID_PAGE;
+
     public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             BaseContainerInterface sizeStrategy) {
         super(context, attrs, defStyleAttr);
@@ -989,8 +998,7 @@
         if (mHandleTaskStackChanges) {
             TaskView taskView = getTaskViewByTaskId(taskId);
             if (taskView != null) {
-                for (TaskIdAttributeContainer container :
-                        taskView.getTaskIdAttributeContainers()) {
+                for (TaskContainer container : taskView.getTaskContainers()) {
                     if (container == null || taskId != container.getTask().key.id) {
                         continue;
                     }
@@ -1005,11 +1013,12 @@
     public void onTaskIconChanged(String pkg, UserHandle user) {
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView tv = requireTaskViewAt(i);
-            Task task = tv.getTask();
+            Task task = tv.getFirstTask();
             if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
                     && task.key.userId == user.getIdentifier()) {
                 task.icon = null;
-                if (tv.getIconView().getDrawable() != null) {
+                TaskViewIcon firstIconView = tv.getFirstIconView();
+                if (firstIconView != null && firstIconView.getDrawable() != null) {
                     tv.onTaskListVisibilityChanged(true /* visible */);
                 }
             }
@@ -1040,13 +1049,14 @@
                 continue;
             }
             // taskView could be a GroupedTaskView, so select the relevant task by ID
-            TaskIdAttributeContainer taskAttributes = taskView.getTaskAttributesById(id);
+            TaskContainer taskAttributes = taskView.getTaskContainerById(id);
             if (taskAttributes == null) {
                 continue;
             }
             Task task = taskAttributes.getTask();
-            TaskThumbnailView taskThumbnailView = taskAttributes.getThumbnailView();
-            taskThumbnailView.setThumbnail(task, thumbnail, refreshNow);
+            TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
+                    taskAttributes.getThumbnailView();
+            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;
@@ -1411,7 +1421,7 @@
      */
     @Nullable
     public TaskView getTaskViewByTaskIds(int[] taskIds) {
-        if (!hasAnyValidTaskIds(taskIds)) {
+        if (!hasAllValidTaskIds(taskIds)) {
             return null;
         }
 
@@ -1430,9 +1440,11 @@
         return null;
     }
 
-    /** Returns false if {@code taskIds} is null or contains invalid values, true otherwise */
-    private boolean hasAnyValidTaskIds(int[] taskIds) {
-        return taskIds != null && !Arrays.equals(taskIds, INVALID_TASK_IDS);
+    /** Returns false if {@code taskIds} is null or contains any invalid values, true otherwise */
+    private boolean hasAllValidTaskIds(int[] taskIds) {
+        return taskIds != null
+                && taskIds.length > 0
+                && Arrays.stream(taskIds).noneMatch(taskId -> taskId == INVALID_TASK_ID);
     }
 
     public void setOverviewStateEnabled(boolean enabled) {
@@ -1705,6 +1717,12 @@
             return;
         }
 
+        if (taskGroups == null) {
+            Log.d(TAG, "applyLoadPlan - taskGroups is null");
+        } else {
+            Log.d(TAG, "applyLoadPlan - taskGroups: " + taskGroups.stream().map(
+                    GroupTask::toString).toList());
+        }
         mLoadPlanEverApplied = true;
         if (taskGroups == null || taskGroups.isEmpty()) {
             removeTasksViewsAndClearAllButton();
@@ -1718,10 +1736,12 @@
             return;
         }
 
-        int[] currentTaskId = INVALID_TASK_IDS;
+        int[] currentTaskIds;
         TaskView currentTaskView = getTaskViewAt(mCurrentPage);
-        if (currentTaskView != null && currentTaskView.getTask() != null) {
-            currentTaskId = currentTaskView.getTaskIds();
+        if (currentTaskView != null && currentTaskView.getFirstTask() != null) {
+            currentTaskIds = currentTaskView.getTaskIds();
+        } else {
+            currentTaskIds = new int[0];
         }
 
         // Unload existing visible task data
@@ -1733,8 +1753,8 @@
 
         // Save running task ID if it exists before rebinding all taskViews, otherwise the task from
         // the runningTaskView currently bound could get assigned to another TaskView
-        int[] runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId);
-        int[] focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId);
+        int[] runningTaskIds = getTaskIdsForTaskViewId(mRunningTaskViewId);
+        int[] focusedTaskIds = getTaskIdsForTaskViewId(mFocusedTaskViewId);
 
         // Reset the focused task to avoiding initializing TaskViews layout as focused task during
         // binding. The focused task view will be updated after all the TaskViews are bound.
@@ -1817,7 +1837,7 @@
         }
 
         // Keep same previous focused task
-        TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskId);
+        TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
         // If the list changed, maybe the focused task doesn't exist anymore
         if (newFocusedTaskView == null && getTaskViewCount() > 0) {
             newFocusedTaskView = getTaskViewAt(0);
@@ -1828,12 +1848,12 @@
         updateChildTaskOrientations();
 
         TaskView newRunningTaskView = null;
-        if (hasAnyValidTaskIds(runningTaskId)) {
+        if (hasAllValidTaskIds(runningTaskIds)) {
             // Update mRunningTaskViewId to be the new TaskView that was assigned by binding
             // the full list of tasks to taskViews
-            newRunningTaskView = getTaskViewByTaskIds(runningTaskId);
+            newRunningTaskView = getTaskViewByTaskIds(runningTaskIds);
             if (newRunningTaskView != null) {
-                mRunningTaskViewId = newRunningTaskView.getTaskViewId();
+                setRunningTaskViewId(newRunningTaskView.getTaskViewId());
             } else {
                 if (mActiveGestureRunningTasks != null) {
                     // This will update mRunningTaskViewId and create a stub view if necessary.
@@ -1842,7 +1862,7 @@
                     // the current running task is excludedFromRecents.)
                     showCurrentTask(mActiveGestureRunningTasks);
                 } else {
-                    mRunningTaskViewId = INVALID_TASK_ID;
+                    setRunningTaskViewId(INVALID_TASK_ID);
                 }
             }
         }
@@ -1851,8 +1871,8 @@
         if (mNextPage != INVALID_PAGE) {
             // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
             mCurrentPage = previousCurrentPage;
-            if (hasAnyValidTaskIds(currentTaskId)) {
-                currentTaskView = getTaskViewByTaskIds(currentTaskId);
+            if (hasAllValidTaskIds(currentTaskIds)) {
+                currentTaskView = getTaskViewByTaskIds(currentTaskIds);
                 if (currentTaskView != null) {
                     targetPage = indexOfChild(currentTaskView);
                 }
@@ -1861,7 +1881,7 @@
             targetPage = previousFocusedPage;
         } else {
             // Set the current page to the running task, but not if settling on new task.
-            if (hasAnyValidTaskIds(runningTaskId)) {
+            if (hasAllValidTaskIds(runningTaskIds)) {
                 targetPage = indexOfChild(newRunningTaskView);
             } else if (getTaskViewCount() > 0) {
                 targetPage = indexOfChild(requireTaskViewAt(0));
@@ -1961,7 +1981,8 @@
     public void resetTaskVisuals() {
         for (int i = getTaskViewCount() - 1; i >= 0; i--) {
             TaskView taskView = requireTaskViewAt(i);
-            if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) {
+            if (Arrays.stream(taskView.getTaskIds()).noneMatch(
+                    taskId -> taskId == mIgnoreResetTaskId)) {
                 taskView.resetViewTransforms();
                 taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
                 taskView.setStableAlpha(mContentAlpha);
@@ -1998,6 +2019,9 @@
 
     public void setFullscreenProgress(float fullscreenProgress) {
         mFullscreenProgress = fullscreenProgress;
+        if (enableRefactorTaskThumbnail()) {
+            mRecentsViewData.getFullscreenProgress().setValue(mFullscreenProgress);
+        }
         int taskCount = getTaskViewCount();
         for (int i = 0; i < taskCount; i++) {
             requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
@@ -2005,7 +2029,7 @@
         mClearAllButton.setFullscreenProgress(fullscreenProgress);
 
         // Fade out the actions view quickly (0.1 range)
-        mActionsView.getFullscreenAlpha().setValue(
+        mActionsView.getFullscreenAlphaSetter().accept(
                 mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
     }
 
@@ -2256,8 +2280,8 @@
     }
 
     private void animateActionsViewAlpha(float alphaValue, long duration) {
-        mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
-                mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue);
+        mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(mActionsView.getVisibilityAlphaSetter(),
+                OverviewActionsView.FLOAT_SETTER, alphaValue);
         mActionsViewAlphaAnimatorFinalValue = alphaValue;
         mActionsViewAlphaAnimator.setDuration(duration);
         // Set autocancel to prevent race-conditiony setting of alpha from other animations
@@ -2276,7 +2300,7 @@
         mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
 
         // Clear all button alpha was set by the previous line.
-        mActionsView.getIndexScrollAlpha().setValue(1 - mClearAllButton.getScrollAlpha());
+        mActionsView.getIndexScrollAlphaSetter().accept(1 - mClearAllButton.getScrollAlpha());
     }
 
     @Override
@@ -2340,8 +2364,8 @@
         // Update the task data for the in/visible children
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView taskView = requireTaskViewAt(i);
-            TaskIdAttributeContainer[] containers = taskView.getTaskIdAttributeContainers();
-            if (containers[0] == null && containers[1] == null) {
+            List<TaskContainer> containers = taskView.getTaskContainers();
+            if (containers.isEmpty()) {
                 continue;
             }
             int index = indexOfChild(taskView);
@@ -2353,8 +2377,8 @@
             }
             if (visible) {
                 // Default update all non-null tasks, then remove running ones
-                List<Task> tasksToUpdate = Arrays.stream(containers).filter(Objects::nonNull)
-                        .map(TaskIdAttributeContainer::getTask)
+                List<Task> tasksToUpdate = containers.stream()
+                        .map(TaskContainer::getTask)
                         .collect(Collectors.toCollection(ArrayList::new));
                 if (mTmpRunningTasks != null) {
                     for (Task t : mTmpRunningTasks) {
@@ -2379,7 +2403,7 @@
                     mHasVisibleTaskData.put(task.key.id, visible);
                 }
             } else {
-                for (TaskIdAttributeContainer container : containers) {
+                for (TaskContainer container : containers) {
                     if (container == null) {
                         continue;
                     }
@@ -2496,7 +2520,7 @@
         // For now 2 distinct task IDs is max for split screen
         TaskView runningTaskView = getTaskViewFromTaskViewId(taskViewId);
         if (runningTaskView == null) {
-            return INVALID_TASK_IDS;
+            return new int[0];
         }
 
         return runningTaskView.getTaskIds();
@@ -2585,7 +2609,7 @@
      */
     public void onGestureAnimationStart(
             Task[] runningTasks, RotationTouchHelper rotationTouchHelper) {
-        Log.d(TAG, "onGestureAnimationStart");
+        Log.d(TAG, "onGestureAnimationStart - runningTasks: " + Arrays.toString(runningTasks));
         mActiveGestureRunningTasks = runningTasks;
         // This needs to be called before the other states are set since it can create the task view
         if (mOrientationState.setGestureActive(true)) {
@@ -2734,18 +2758,19 @@
      * Returns true if we should add a stub taskView for the running task id
      */
     protected boolean shouldAddStubTaskView(Task[] runningTasks) {
-        if (runningTasks.length > 1) {
-            TaskView primaryTaskView = getTaskViewByTaskId(runningTasks[0].key.id);
-            TaskView secondaryTaskView = getTaskViewByTaskId(runningTasks[1].key.id);
-            int leftTopTaskViewId =
-                    (primaryTaskView == null) ? -1 : primaryTaskView.getTaskViewId();
-            int rightBottomTaskViewId =
-                    (secondaryTaskView == null) ? -1 : secondaryTaskView.getTaskViewId();
-            // Add a new stub view if both taskIds don't match any taskViews
-            return leftTopTaskViewId != rightBottomTaskViewId || leftTopTaskViewId == -1;
+        int[] runningTaskIds = Arrays.stream(runningTasks).mapToInt(task -> task.key.id).toArray();
+        TaskView matchingTaskView = null;
+        if (hasDesktopTask(runningTasks) && runningTaskIds.length == 1) {
+            // TODO(b/249371338): Unsure if it's expected, desktop runningTasks only have a single
+            // taskId, therefore we match any DesktopTaskView that contains the runningTaskId.
+            TaskView taskview = getTaskViewByTaskId(runningTaskIds[0]);
+            if (taskview instanceof DesktopTaskView) {
+                matchingTaskView = taskview;
+            }
+        } else {
+            matchingTaskView = getTaskViewByTaskIds(runningTaskIds);
         }
-        Task runningTaskInfo = runningTasks[0];
-        return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.key.id) == null;
+        return matchingTaskView == null;
     }
 
     /**
@@ -2755,6 +2780,7 @@
      * is called.  Also scrolls the view to this task.
      */
     private void showCurrentTask(Task[] runningTasks) {
+        Log.d(TAG, "showCurrentTask - runningTasks: " + Arrays.toString(runningTasks));
         if (runningTasks.length == 0) {
             return;
         }
@@ -2817,7 +2843,7 @@
     }
 
     private boolean hasDesktopTask(Task[] runningTasks) {
-        if (!enableDesktopWindowingMode()) {
+        if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
             return false;
         }
         for (Task task : runningTasks) {
@@ -2842,7 +2868,23 @@
             setRunningTaskViewShowScreenshot(true);
             setRunningTaskHidden(false);
         }
+        setRunningTaskViewId(runningTaskViewId);
+    }
+
+    private void setRunningTaskViewId(int runningTaskViewId) {
+        int prevRunningTaskViewId = mRunningTaskViewId;
         mRunningTaskViewId = runningTaskViewId;
+
+        if (Flags.enableRefactorTaskThumbnail()) {
+            TaskView previousRunningTaskView = getTaskViewFromTaskViewId(prevRunningTaskViewId);
+            if (previousRunningTaskView != null) {
+                previousRunningTaskView.notifyIsRunningTaskUpdated();
+            }
+            TaskView newRunningTaskView = getTaskViewFromTaskViewId(runningTaskViewId);
+            if (newRunningTaskView != null) {
+                newRunningTaskView.notifyIsRunningTaskUpdated();
+            }
+        }
     }
 
     private int getTaskViewIdFromTaskId(int taskId) {
@@ -3784,7 +3826,7 @@
 
                 if (success) {
                     if (shouldRemoveTask) {
-                        if (dismissedTaskView.getTask() != null) {
+                        if (dismissedTaskView.getFirstTask() != null) {
                             if (dismissedTaskView.isRunningTask()) {
                                 finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
                                         () -> removeTaskInternal(dismissedTaskViewId));
@@ -3979,7 +4021,9 @@
      * * Device is large screen
      */
     private void updateCurrentTaskActionsVisibility() {
-        boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
+        TaskView taskView = getCurrentPageTaskView();
+        boolean isCurrentSplit = taskView instanceof GroupedTaskView;
+        GroupedTaskView groupedTaskView = isCurrentSplit ? (GroupedTaskView) taskView : null;
         // Update flags to see if entire actions bar should be hidden.
         if (!FeatureFlags.enableAppPairs()) {
             mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
@@ -3987,9 +4031,11 @@
         mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
         // Update flags to see if actions bar should show buttons for a single task or a pair of
         // tasks.
-        mActionsView.updateForGroupedTask(isCurrentSplit);
+        boolean canSaveAppPair = isCurrentSplit && supportsAppPairs() &&
+                getSplitSelectController().getAppPairsController().canSaveAppPair(groupedTaskView);
+        mActionsView.updateForGroupedTask(isCurrentSplit, canSaveAppPair);
 
-        boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
+        boolean isCurrentDesktop = taskView instanceof DesktopTaskView;
         mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
     }
 
@@ -4251,13 +4297,10 @@
         alpha = Utilities.boundToRange(alpha, 0, 1);
         mContentAlpha = alpha;
 
-        int runningTaskId = getTaskIdsForRunningTaskView()[0];
+        TaskView runningTaskView = getRunningTaskView();
         for (int i = getTaskViewCount() - 1; i >= 0; i--) {
             TaskView child = requireTaskViewAt(i);
-            int[] childTaskIds = child.getTaskIds();
-            if (runningTaskId != INVALID_TASK_ID
-                    && mRunningTaskTileHidden
-                    && (childTaskIds[0] == runningTaskId || childTaskIds[1] == runningTaskId)) {
+            if (runningTaskView != null && mRunningTaskTileHidden && child == runningTaskView) {
                 continue;
             }
             child.setStableAlpha(alpha);
@@ -4266,7 +4309,7 @@
         int alphaInt = Math.round(alpha * 255);
         mEmptyMessagePaint.setAlpha(alphaInt);
         mEmptyIcon.setAlpha(alphaInt);
-        mActionsView.getContentAlpha().setValue(mContentAlpha);
+        mActionsView.getContentAlphaSetter().accept(mContentAlpha);
 
         if (alpha > 0) {
             setVisibility(VISIBLE);
@@ -4438,15 +4481,26 @@
         setPivotY(mTempPointF.y);
     }
 
+    /**
+     * Sets whether we should force-override the page offset mid-point to the current task, rather
+     * than the running task, when updating page offsets.
+     */
+    public void setOffsetMidpointIndexOverride(int offsetMidpointIndexOverride) {
+        mOffsetMidpointIndexOverride = offsetMidpointIndexOverride;
+        updatePageOffsets();
+    }
+
     private void updatePageOffsets() {
         float offset = mAdjacentPageHorizontalOffset;
         float modalOffset = ACCELERATE_0_75.getInterpolation(mTaskModalness);
         int count = getChildCount();
         boolean showAsGrid = showAsGrid();
 
-        TaskView runningTask = mRunningTaskViewId == -1 || !mRunningTaskTileHidden
+        TaskView runningTask = mRunningTaskViewId == INVALID_PAGE || !mRunningTaskTileHidden
                 ? null : getRunningTaskView();
-        int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
+        int midpoint = mOffsetMidpointIndexOverride == INVALID_PAGE
+                ? (runningTask == null ? INVALID_PAGE : indexOfChild(runningTask))
+                : mOffsetMidpointIndexOverride;
         int modalMidpoint = getCurrentPage();
         boolean isModalGridWithoutFocusedTask =
                 showAsGrid && enableGridOnlyOverview() && mTaskModalness > 0;
@@ -4690,7 +4744,7 @@
      */
     public void resetModalVisuals() {
         if (mSelectedTask != null) {
-            mSelectedTask.getThumbnail().getTaskOverlay().resetModalVisuals();
+            mSelectedTask.getFirstThumbnailView().getTaskOverlay().resetModalVisuals();
         }
     }
 
@@ -4709,7 +4763,7 @@
             StatsLogManager.EventEnum splitEvent) {
         mSplitHiddenTaskView = taskView;
         mSplitSelectStateController.setInitialTaskSelect(null /*intent*/,
-                stagePosition, taskView.getItemInfo(), splitEvent, taskView.mTask.key.id);
+                stagePosition, taskView.getItemInfo(), splitEvent, taskView.getFirstTask().key.id);
         mSplitSelectStateController.setAnimateCurrentTaskDismissal(
                 true /*animateCurrentTaskDismissal*/);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
@@ -4731,7 +4785,7 @@
 
         // Prevent dismissing whole task if we're only initiating from one of 2 tasks in split pair
         mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
-                && mSplitHiddenTaskView.containsMultipleTasks());
+                && mSplitHiddenTaskView instanceof GroupedTaskView);
         mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
                 splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
                 splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
@@ -4752,19 +4806,19 @@
                 mSplitSelectStateController.isAnimateCurrentTaskDismissal();
         boolean isInitiatingTaskViewSplitPair =
                 mSplitSelectStateController.isDismissingFromSplitPair();
-        if (isInitiatingSplitFromTaskView && isInitiatingTaskViewSplitPair) {
+        if (isInitiatingSplitFromTaskView && isInitiatingTaskViewSplitPair
+                && mSplitHiddenTaskView instanceof GroupedTaskView) {
             // Splitting from Overview for split pair task
             createInitialSplitSelectAnimation(builder);
 
             // Animate pair thumbnail into full thumbnail
-            boolean primaryTaskSelected =
-                    mSplitHiddenTaskView.getTaskIdAttributeContainers()[0].getTask().key.id ==
-                            mSplitSelectStateController.getInitialTaskId();
-            TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
-                    .getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
-            TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
+            boolean primaryTaskSelected = mSplitHiddenTaskView.getTaskIds()[0]
+                    == mSplitSelectStateController.getInitialTaskId();
+            TaskContainer taskContainer = mSplitHiddenTaskView
+                    .getTaskContainers().get(primaryTaskSelected ? 1 : 0);
+            TaskThumbnailViewDeprecated thumbnail = taskContainer.getThumbnailView();
             mSplitSelectStateController.getSplitAnimationController()
-                    .addInitialSplitFromPair(taskIdAttributeContainer, builder,
+                    .addInitialSplitFromPair(taskContainer, builder,
                             mContainer.getDeviceProfile(),
                             mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
                             primaryTaskSelected);
@@ -5162,7 +5216,7 @@
         updateGridProperties();
         updateScrollSynchronously();
 
-        int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+        int targetSysUiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
         final boolean[] passedOverviewThreshold = new boolean[] {false};
         ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
         progressAnim.addUpdateListener(animator -> {
@@ -5210,7 +5264,8 @@
         mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
         mPendingAnimation.addEndListener(isSuccess -> {
             if (isSuccess) {
-                if (tv.getTaskIds()[1] != -1 && mRemoteTargetHandles != null) {
+                if (tv instanceof GroupedTaskView && hasAllValidTaskIds(tv.getTaskIds())
+                        && mRemoteTargetHandles != null) {
                     // TODO(b/194414938): make this part of the animations instead.
                     TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
                             mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
@@ -5225,7 +5280,7 @@
                 } else {
                     tv.launchTask(this::onTaskLaunchAnimationEnd);
                 }
-                Task task = tv.getTask();
+                Task task = tv.getFirstTask();
                 if (task != null) {
                     mContainer.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
                             .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
@@ -5435,8 +5490,9 @@
      * Called when a running recents animation has finished or canceled.
      */
     public void onRecentsAnimationComplete() {
-        Log.d(TAG, "onRecentsAnimationComplete - mRecentsAnimationController: "
-                + mRecentsAnimationController);
+        Log.d(TAG, "onRecentsAnimationComplete "
+                + "- mRecentsAnimationController: " + mRecentsAnimationController
+                + ", mSideTaskLaunchCallback: " + mSideTaskLaunchCallback);
         // At this point, the recents animation is not running and if the animation was canceled
         // by a display rotation then reset this state to show the screenshot
         setRunningTaskViewShowScreenshot(true);
@@ -5857,15 +5913,14 @@
         }
 
         taskView.setShowScreenshot(true);
-        for (TaskIdAttributeContainer container :
-                taskView.getTaskIdAttributeContainers()) {
+        for (TaskContainer container : taskView.getTaskContainers()) {
             if (container == null) {
                 continue;
             }
 
             ThumbnailData td =
                     mRecentsAnimationController.screenshotTask(container.getTask().key.id);
-            TaskThumbnailView thumbnailView = container.getThumbnailView();
+            TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailView();
             if (td != null) {
                 thumbnailView.setThumbnail(container.getTask(), td);
             } else {
@@ -5990,7 +6045,8 @@
     }
 
     public void cleanupRemoteTargets() {
-        Log.d(TAG, "cleanupRemoteTargets");
+        Log.d(TAG, "cleanupRemoteTargets - mRemoteTargetHandles: " + Arrays.toString(
+                mRemoteTargetHandles));
         mRemoteTargetHandles = null;
     }
 
@@ -6227,16 +6283,16 @@
     /**
      * Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded.
      */
-    public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
+    public void moveTaskToDesktop(TaskContainer taskContainer,
             Runnable successCallback) {
-        if (!enableDesktopWindowingMode()) {
+        if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
             return;
         }
         switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false,
                 () -> moveTaskToDesktopInternal(taskContainer, successCallback)));
     }
 
-    private void moveTaskToDesktopInternal(TaskIdAttributeContainer taskContainer,
+    private void moveTaskToDesktopInternal(TaskContainer taskContainer,
             Runnable successCallback) {
         if (mDesktopRecentsTransitionController == null) {
             return;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index fcbb45b..578d471 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -18,11 +18,9 @@
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
+import static com.android.quickstep.views.TaskThumbnailViewDeprecated.DIM_ALPHA;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -56,7 +54,7 @@
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.TaskCornerRadius;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
 
 /**
  * Contains options for a recent task when long-pressing its icon.
@@ -76,7 +74,7 @@
     private ValueAnimator mRevealAnimator;
     @Nullable private Runnable mOnClosingStartCallback;
     private TaskView mTaskView;
-    private TaskIdAttributeContainer mTaskContainer;
+    private TaskContainer mTaskContainer;
     private LinearLayout mOptionLayout;
     private float mMenuTranslationYBeforeOpen;
     private float mMenuTranslationXBeforeOpen;
@@ -163,7 +161,10 @@
         }
     }
 
-    public static boolean showForTask(TaskIdAttributeContainer taskContainer,
+    /**
+     * Show a task menu for the given taskContainer.
+     */
+    public static boolean showForTask(TaskContainer taskContainer,
             @Nullable Runnable onClosingStartCallback) {
         RecentsViewContainer container = RecentsViewContainer.containerFromContext(
                 taskContainer.getTaskView().getContext());
@@ -173,11 +174,14 @@
         return taskMenuView.populateAndShowForTask(taskContainer);
     }
 
-    public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+    /**
+     * Show a task menu for the given taskContainer.
+     */
+    public static boolean showForTask(TaskContainer taskContainer) {
         return showForTask(taskContainer, null);
     }
 
-    private boolean populateAndShowForTask(TaskIdAttributeContainer taskContainer) {
+    private boolean populateAndShowForTask(TaskContainer taskContainer) {
         if (isAttachedToWindow()) {
             return false;
         }
@@ -193,16 +197,12 @@
 
     /** @return true if successfully able to populate task view menu, false otherwise */
     private boolean populateAndLayoutMenu() {
-        if (mTaskContainer.getTask().icon == null) {
-            // Icon may not be loaded
-            return false;
-        }
         addMenuOptions(mTaskContainer);
         orientAroundTaskView(mTaskContainer);
         return true;
     }
 
-    private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
+    private void addMenuOptions(TaskContainer taskContainer) {
         if (enableOverviewIconMenu()) {
             removeView(mTaskName);
         } else {
@@ -230,7 +230,7 @@
         mOptionLayout.addView(menuOptionView);
     }
 
-    private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) {
+    private void orientAroundTaskView(TaskContainer taskContainer) {
         RecentsView recentsView = mContainer.getOverviewPanel();
         RecentsPagedOrientationHandler orientationHandler =
                 recentsView.getPagedOrientationHandler();
@@ -305,7 +305,6 @@
 
     private void animateOpenOrClosed(boolean closing) {
         if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
-            testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "getting canceled");
             mOpenCloseAnimator.cancel();
         }
         mOpenCloseAnimator = new AnimatorSet();
@@ -362,14 +361,10 @@
                     iconAppChip.getMenuTranslationX(),
                     MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
             menuTranslationXAnim.setInterpolator(EMPHASIZED);
-            testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
-                    "TaskMenuView.java.animateOpenOrClosed: running translation animations");
 
             mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
                     menuTranslationXAnim, menuTranslationYAnim);
         }
-        testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
-                "TaskMenuView.java.animateOpenOrClosed: running animation 2");
         mOpenCloseAnimator.playTogether(mRevealAnimator,
                 ObjectAnimator.ofFloat(
                         mTaskContainer.getThumbnailView(), DIM_ALPHA,
@@ -378,8 +373,6 @@
         mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
-                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
-                        "TaskMenuView.java.animateOpenOrClosed: onAnimationStart");
                 setVisibility(VISIBLE);
                 if (closing && mOnClosingStartCallback != null) {
                     mOnClosingStartCallback.run();
@@ -387,16 +380,7 @@
             }
 
             @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
-                        "TaskMenuView.java.animateOpenOrClosed: onAnimationCancel");
-            }
-
-            @Override
             public void onAnimationSuccess(Animator animator) {
-                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
-                        "TaskMenuView.java.animateOpenOrClosed: onAnimationSuccess");
                 if (closing) {
                     closeComplete();
                 }
@@ -407,7 +391,6 @@
     }
 
     private void closeComplete() {
-        testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "TaskMenuView.java.closeComplete");
         mIsOpen = false;
         mContainer.getDragLayer().removeView(this);
         mRevealAnimator = null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index c124f03..7adc32e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -37,14 +37,14 @@
 import com.android.launcher3.popup.SystemShortcut
 import com.android.launcher3.util.Themes
 import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
 
 class TaskMenuViewWithArrow<T> : ArrowPopup<T> where T : RecentsViewContainer, T : Context {
     companion object {
         const val TAG = "TaskMenuViewWithArrow"
 
         fun <T> showForTask(
-            taskContainer: TaskIdAttributeContainer,
+            taskContainer: TaskContainer,
             alignedOptionIndex: Int = 0
         ): Boolean where T : RecentsViewContainer, T : Context {
             val container: RecentsViewContainer =
@@ -83,11 +83,11 @@
     private var alignedOptionIndex: Int = 0
     private val extraSpaceForRowAlignment: Int
         get() = optionMeasuredHeight * alignedOptionIndex
-    private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
+    private val menuPaddingEnd = context.resources.getDimensionPixelSize(R.dimen.task_card_margin)
 
     private lateinit var taskView: TaskView
     private lateinit var optionLayout: LinearLayout
-    private lateinit var taskContainer: TaskIdAttributeContainer
+    private lateinit var taskContainer: TaskContainer
 
     private var optionMeasuredHeight = 0
     private val arrowHorizontalPadding: Int
@@ -141,7 +141,7 @@
     }
 
     private fun populateAndShowForTask(
-        taskContainer: TaskIdAttributeContainer,
+        taskContainer: TaskContainer,
         alignedOptionIndex: Int
     ): Boolean {
         if (isAttachedToWindow) {
@@ -174,10 +174,10 @@
     /** @return true if successfully able to populate task view menu, false otherwise */
     private fun populateMenu(): Boolean {
         // Icon may not be loaded
-        if (taskContainer.task.icon == null) return false
+        if (taskContainer.iconView.drawable == null) return false
 
         addMenuOptions()
-        return true
+        return optionLayout.childCount > 0
     }
 
     private fun addMenuOptions() {
@@ -213,7 +213,13 @@
             menuOptionView.requireViewById(R.id.text)
         )
         val lp = menuOptionView.layoutParams as LayoutParams
-        lp.width = menuWidth
+        lp.width = LayoutParams.MATCH_PARENT
+        menuOptionView.setPaddingRelative(
+            menuOptionView.paddingStart,
+            menuOptionView.paddingTop,
+            menuPaddingEnd,
+            menuOptionView.paddingBottom
+        )
         menuOptionView.setOnClickListener { view: View? -> menuOption.onClick(view) }
         optionLayout.addView(menuOptionView)
     }
@@ -347,7 +353,7 @@
 
     override fun updateArrowColor() {
         mArrow.background =
-            RoundedArrowDrawable(
+            RoundedArrowDrawable.createHorizontalRoundedArrow(
                 mArrowWidth.toFloat(),
                 mArrowHeight.toFloat(),
                 mArrowPointRadius.toFloat(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
similarity index 91%
rename from quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
rename to quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 7e46739..21c6ca8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -53,6 +53,7 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
+import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
@@ -62,61 +63,66 @@
 
 /**
  * A task in the Recents view.
+ *
+ * @deprecated This class will be replaced by the new [TaskThumbnailView].
  */
-public class TaskThumbnailView extends View {
+@Deprecated
+public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusable {
     private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
             new MainThreadInitializedObject<>(FullscreenDrawParams::new);
 
-    public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
-            new FloatProperty<TaskThumbnailView>("dimAlpha") {
+    public static final Property<TaskThumbnailViewDeprecated, Float> DIM_ALPHA =
+            new FloatProperty<TaskThumbnailViewDeprecated>("dimAlpha") {
                 @Override
-                public void setValue(TaskThumbnailView thumbnail, float dimAlpha) {
+                public void setValue(TaskThumbnailViewDeprecated thumbnail, float dimAlpha) {
                     thumbnail.setDimAlpha(dimAlpha);
                 }
 
                 @Override
-                public Float get(TaskThumbnailView thumbnailView) {
+                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
                     return thumbnailView.mDimAlpha;
                 }
             };
 
-    public static final Property<TaskThumbnailView, Float> SPLASH_ALPHA =
-            new FloatProperty<TaskThumbnailView>("splashAlpha") {
+    public static final Property<TaskThumbnailViewDeprecated, Float> SPLASH_ALPHA =
+            new FloatProperty<TaskThumbnailViewDeprecated>("splashAlpha") {
                 @Override
-                public void setValue(TaskThumbnailView thumbnail, float splashAlpha) {
+                public void setValue(TaskThumbnailViewDeprecated thumbnail, float splashAlpha) {
                     thumbnail.setSplashAlpha(splashAlpha);
                 }
 
                 @Override
-                public Float get(TaskThumbnailView thumbnailView) {
+                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
                     return thumbnailView.mSplashAlpha / 255f;
                 }
             };
 
     /** Use to animate thumbnail translationX while first app in split selection is initiated */
-    public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_X =
-            new FloatProperty<TaskThumbnailView>("splitSelectTranslateX") {
+    public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_X =
+            new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateX") {
                 @Override
-                public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateX) {
+                public void setValue(TaskThumbnailViewDeprecated thumbnail,
+                        float splitSelectTranslateX) {
                     thumbnail.applySplitSelectTranslateX(splitSelectTranslateX);
                 }
 
                 @Override
-                public Float get(TaskThumbnailView thumbnailView) {
+                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
                     return thumbnailView.mSplitSelectTranslateX;
                 }
             };
 
     /** Use to animate thumbnail translationY while first app in split selection is initiated */
-    public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_Y =
-            new FloatProperty<TaskThumbnailView>("splitSelectTranslateY") {
+    public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_Y =
+            new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateY") {
                 @Override
-                public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateY) {
+                public void setValue(TaskThumbnailViewDeprecated thumbnail,
+                        float splitSelectTranslateY) {
                     thumbnail.applySplitSelectTranslateY(splitSelectTranslateY);
                 }
 
                 @Override
-                public Float get(TaskThumbnailView thumbnailView) {
+                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
                     return thumbnailView.mSplitSelectTranslateY;
                 }
             };
@@ -156,15 +162,16 @@
     private float mSplitSelectTranslateX;
     private float mSplitSelectTranslateY;
 
-    public TaskThumbnailView(Context context) {
+    public TaskThumbnailViewDeprecated(Context context) {
         this(context, null);
     }
 
-    public TaskThumbnailView(Context context, @Nullable AttributeSet attrs) {
+    public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public TaskThumbnailView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+    public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
@@ -180,7 +187,6 @@
 
     /**
      * Updates the thumbnail to draw the provided task
-     * @param task
      */
     public void bind(Task task) {
         getTaskOverlay().reset();
@@ -194,6 +200,7 @@
 
     /**
      * Updates the thumbnail.
+     *
      * @param refreshNow whether the {@code thumbnailData} will be used to redraw immediately.
      *                   In most cases, we use the {@link #setThumbnail(Task, ThumbnailData)}
      *                   version with {@code refreshNow} is true. The only exception is
@@ -227,6 +234,7 @@
 
     /**
      * Updates the shader, paint, matrix to redraw.
+     *
      * @param shouldRefreshOverlay whether to re-initialize overlay
      */
     private void refresh(boolean shouldRefreshOverlay) {
@@ -253,7 +261,6 @@
      * <p>
      * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
      * extracted background color.
-     *
      */
     public void setDimAlpha(float dimAlpha) {
         mDimAlpha = dimAlpha;
@@ -286,6 +293,7 @@
     /**
      * Get the scaled insets that are being used to draw the task view. This is a subsection of
      * the full snapshot.
+     *
      * @return the insets in snapshot bitmap coordinates.
      */
     @RequiresApi(api = Build.VERSION_CODES.Q)
@@ -599,4 +607,9 @@
         }
         return mThumbnailData.isRealSnapshot && !mTask.isLocked;
     }
+
+    @Override
+    public void onRecycle() {
+        // Do nothing
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ec57115..1187222 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -16,7 +16,6 @@
 
 package com.android.quickstep.views;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.widget.Toast.LENGTH_SHORT;
 
@@ -25,13 +24,12 @@
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 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.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -49,7 +47,6 @@
 import android.animation.ObjectAnimator;
 import android.annotation.IdRes;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -93,6 +90,7 @@
 import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.TraceHelper;
@@ -107,6 +105,9 @@
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.task.thumbnail.TaskThumbnail;
+import com.android.quickstep.task.thumbnail.TaskThumbnailView;
+import com.android.quickstep.task.viewmodel.TaskViewData;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.util.RecentsOrientedState;
@@ -118,22 +119,24 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 
+import kotlin.Unit;
+
 import java.lang.annotation.Retention;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 
-import kotlin.Unit;
 
 /**
  * A task in the Recents view.
  */
 public class TaskView extends FrameLayout implements Reusable {
 
-    private static final String TAG = TaskView.class.getSimpleName();
+    private static final String TAG = "TaskView";
     public static final int FLAG_UPDATE_ICON = 1;
     public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
     public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
@@ -147,7 +150,8 @@
      */
     @Retention(SOURCE)
     @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL, FLAG_UPDATE_CORNER_RADIUS})
-    public @interface TaskDataChanges {}
+    public @interface TaskDataChanges {
+    }
 
     /**
      * Type of task view
@@ -319,13 +323,13 @@
 
                 @Override
                 public Float get(TaskView taskView) {
-                    return taskView.mSnapshotView.getScaleX();
+                    return taskView.mTaskThumbnailViewDeprecated.getScaleX();
                 }
             };
 
-    @Nullable
-    protected Task mTask;
-    protected TaskThumbnailView mSnapshotView;
+    public TaskViewData mTaskViewData = new TaskViewData();
+    protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
+    protected TaskThumbnailView mTaskThumbnailView;
     protected TaskViewIcon mIconView;
     protected final DigitalWellBeingToast mDigitalWellBeingToast;
     protected float mFullscreenProgress;
@@ -366,12 +370,7 @@
     private float mStableAlpha = 1;
 
     private int mTaskViewId = -1;
-    /**
-     * Index 0 will contain taskID of left/top task, index 1 will contain taskId of bottom/right
-     */
-    protected int[] mTaskIdContainer = new int[]{-1, -1};
-    protected TaskIdAttributeContainer[] mTaskIdAttributeContainer =
-            new TaskIdAttributeContainer[2];
+    protected List<TaskContainer> mTaskContainers = Collections.emptyList();
 
     private boolean mShowScreenshot;
     private boolean mBorderEnabled;
@@ -390,9 +389,11 @@
 
     private boolean mIsClickableAsLiveTile = true;
 
-    @Nullable private final BorderAnimator mFocusBorderAnimator;
+    @Nullable
+    private final BorderAnimator mFocusBorderAnimator;
 
-    @Nullable private final BorderAnimator mHoverBorderAnimator;
+    @Nullable
+    private final BorderAnimator mHoverBorderAnimator;
 
     public TaskView(Context context) {
         this(context, null);
@@ -439,7 +440,7 @@
                     /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
                     /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
                             R.dimen.keyboard_quick_switch_border_width),
-                    /* boundsBuilder= */ this::updateBorderBounds,
+                    /* boundsBuilder= */ this::getThumbnailBounds,
                     /* targetView= */ this,
                     /* borderColor= */ styledAttrs.getColor(
                             R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR))
@@ -454,7 +455,7 @@
                     /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
                     /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
                             R.dimen.task_hover_border_width),
-                    /* boundsBuilder= */ this::updateBorderBounds,
+                    /* boundsBuilder= */ this::getThumbnailBounds,
                     /* targetView= */ this,
                     /* borderColor= */ styledAttrs.getColor(
                             R.styleable.TaskView_hoverBorderColor, DEFAULT_BORDER_COLOR))
@@ -463,11 +464,23 @@
         styledAttrs.recycle();
     }
 
-    protected Unit updateBorderBounds(@NonNull Rect bounds) {
-        bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
-                mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
-                mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
-                mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
+    /** Returns the thumbnail's bounds relative to this view. */
+    public Unit getThumbnailBounds(@NonNull Rect bounds) {
+        return getThumbnailBounds(bounds, false);
+    }
+
+    /** Returns the thumbnail's bounds, optionally relative to the screen. */
+    public Unit getThumbnailBounds(@NonNull Rect bounds, boolean relativeToDragLayer) {
+        View snapshotView = getSnapshotView();
+
+        if (relativeToDragLayer) {
+            mContainer.getDragLayer().getDescendantRectRelativeToSelf(snapshotView, bounds);
+        } else {
+            bounds.set(snapshotView.getLeft() + Math.round(snapshotView.getTranslationX()),
+                    snapshotView.getTop() + Math.round(snapshotView.getTranslationY()),
+                    snapshotView.getRight() + Math.round(snapshotView.getTranslationX()),
+                    snapshotView.getBottom() + Math.round(snapshotView.getTranslationY()));
+        }
         return Unit.INSTANCE;
     }
 
@@ -480,10 +493,24 @@
     }
 
     /**
-     * Builds proto for logging
+     * Updates [TaskThumbnailView] to reflect the latest [Task] state (i.e., task isRunning).
      */
+    public void notifyIsRunningTaskUpdated() {
+        // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
+        //  so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
+        if (!mTaskContainers.isEmpty()) {
+            bindTaskThumbnailView();
+        }
+    }
+
+    /**
+     * Builds proto for logging.
+     *
+     * @deprecated Use {@link #getItemInfo(Task)} instead.
+     */
+    @Deprecated
     public WorkspaceItemInfo getItemInfo() {
-        return getItemInfo(mTask);
+        return getItemInfo(getFirstTask());
     }
 
     /**
@@ -516,7 +543,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mSnapshotView = findViewById(R.id.snapshot);
+        mTaskThumbnailViewDeprecated = findViewById(R.id.snapshot);
+        if (enableRefactorTaskThumbnail()) {
+            mTaskThumbnailView = new TaskThumbnailView(mContext);
+            mTaskThumbnailView.setLayoutParams(mTaskThumbnailViewDeprecated.getLayoutParams());
+            int indexOfSnapshotView = indexOfChild(mTaskThumbnailViewDeprecated);
+            addView(mTaskThumbnailView, indexOfSnapshotView);
+            mTaskThumbnailViewDeprecated.setVisibility(View.GONE);
+        }
         ViewStub iconViewStub = findViewById(R.id.icon);
         if (enableOverviewIconMenu()) {
             iconViewStub.setLayoutResource(R.layout.icon_app_chip_view);
@@ -559,6 +593,10 @@
      * Enable or disable showing border on hover and focus change
      */
     public void setBorderEnabled(boolean enabled) {
+        if (mBorderEnabled == enabled) {
+            return;
+        }
+
         mBorderEnabled = enabled;
         // Set the animation correctly in case it misses the hover/focus event during state
         // transition
@@ -649,20 +687,31 @@
      */
     public void bind(Task task, RecentsOrientedState orientedState) {
         cancelPendingLoadTasks();
-        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.bind: task=" + task);
-        mTask = task;
-        mTaskIdContainer[0] = mTask.key.id;
-        mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
-                STAGE_POSITION_UNDEFINED);
-        mSnapshotView.bind(task);
+        mTaskContainers = Collections.singletonList(
+                new TaskContainer(task, mTaskThumbnailViewDeprecated, mIconView,
+                        STAGE_POSITION_UNDEFINED, mDigitalWellBeingToast));
+        if (enableRefactorTaskThumbnail()) {
+            bindTaskThumbnailView();
+        } else {
+            mTaskThumbnailViewDeprecated.bind(task);
+        }
         setOrientationState(orientedState);
     }
 
+    private void bindTaskThumbnailView() {
+        // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
+        //  so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
+        mTaskThumbnailView.getViewModel().bind(new TaskThumbnail(getFirstTask(), isRunningTask()));
+    }
+
     /**
      * Sets up an on-click listener and the visibility for show_windows icon on top of the task.
      */
     public void setUpShowAllInstancesListener() {
-        String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName();
+        if (mTaskContainers.isEmpty()) {
+            return;
+        }
+        String taskPackageName = mTaskContainers.get(0).getTask().key.getPackageName();
 
         // icon of the top/left task
         View showWindowsView = findViewById(R.id.show_windows);
@@ -704,78 +753,101 @@
         filterView.setOnClickListener(callback);
     }
 
-    public TaskIdAttributeContainer[] getTaskIdAttributeContainers() {
-        return mTaskIdAttributeContainer;
+    /**
+     * Returns a list of all TaskContainers in the TaskView.
+     */
+    public List<TaskContainer> getTaskContainers() {
+        return mTaskContainers;
     }
 
+    /**
+     * Returns the first task bound to this TaskView.
+     *
+     * @deprecated Use {@link #mTaskContainers} instead.
+     */
+    @Deprecated
     @Nullable
-    public Task getTask() {
-        return mTask;
+    public Task getFirstTask() {
+        return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getTask() : null;
     }
 
     /**
      * Check if given {@code taskId} is tracked in this view
      */
     public boolean containsTaskId(int taskId) {
-        return mTask != null && mTask.key.id == taskId;
+        return getTaskContainerById(taskId) != null;
     }
 
     /**
-     * @return integer array of two elements to be size consistent with max number of tasks possible
-     *         index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value
+     * Returns a copy of integer array containing taskIds of all tasks in the TaskView.
      */
     public int[] getTaskIds() {
-        return Arrays.copyOf(mTaskIdContainer, mTaskIdContainer.length);
+        return mTaskContainers.stream().mapToInt(
+                container -> container.getTask().key.id).toArray();
     }
 
     public boolean containsMultipleTasks() {
-        return mTaskIdContainer[1] != -1;
+        return mTaskContainers.size() > 1;
     }
 
     /**
-     * Returns the TaskIdAttributeContainer corresponding to a given taskId, or null if the TaskView
-     * does not contain a Task with that ID.
+     * Returns the TaskContainer corresponding to a given taskId, or null if the TaskView does
+     * not contain a Task with that ID.
      */
     @Nullable
-    public TaskIdAttributeContainer getTaskAttributesById(int taskId) {
-        for (TaskIdAttributeContainer attributes : mTaskIdAttributeContainer) {
-            if (attributes.getTask().key.id == taskId) {
-                return attributes;
-            }
-        }
-
-        return null;
+    public TaskContainer getTaskContainerById(int taskId) {
+        return mTaskContainers.stream().filter(
+                container -> container.getTask().key.id == taskId).findFirst().orElse(null);
     }
 
-    public TaskThumbnailView getThumbnail() {
-        return mSnapshotView;
+    /**
+     * Returns the first thumbnailView of the TaskView.
+     *
+     * @deprecated Use {@link #mTaskContainers} instead.
+     */
+    @Deprecated
+    public TaskThumbnailViewDeprecated getFirstThumbnailView() {
+        return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getThumbnailView()
+                : mTaskThumbnailViewDeprecated;
     }
 
     void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
-        if (mTask != null && thumbnailDatas != null) {
-            final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
+        if (enableRefactorTaskThumbnail()) {
+            // TODO(b/334825222) add thumbnail logic
+            return;
+        }
+        if (getFirstTask() != null && thumbnailDatas != null) {
+            final ThumbnailData thumbnailData = thumbnailDatas.get(getFirstTask().key.id);
             if (thumbnailData != null) {
-                mSnapshotView.setThumbnail(mTask, thumbnailData);
+                mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), thumbnailData);
                 return;
             }
         }
 
-        mSnapshotView.refresh();
+        mTaskThumbnailViewDeprecated.refresh();
     }
 
-    /** TODO(b/197033698) Remove all usages of above method and migrate to this one */
-    public TaskThumbnailView[] getThumbnails() {
-        return new TaskThumbnailView[]{mSnapshotView};
+    public TaskThumbnailViewDeprecated[] getThumbnailViews() {
+        return mTaskContainers.stream().map(
+                TaskContainer::getThumbnailView).toArray(
+                TaskThumbnailViewDeprecated[]::new);
     }
 
-    public TaskViewIcon getIconView() {
-        return mIconView;
+    /**
+     * Returns the first iconView of the TaskView.
+     *
+     * @deprecated Use {@link #mTaskContainers} instead.
+     */
+    @Deprecated
+    @Nullable
+    public TaskViewIcon getFirstIconView() {
+        return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getIconView() : null;
     }
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         RecentsView recentsView = getRecentsView();
-        if (recentsView == null || getTask() == null) {
+        if (recentsView == null || getFirstTask() == null) {
             return false;
         }
         SplitSelectStateController splitSelectStateController =
@@ -783,7 +855,7 @@
         // Disable taps for split selection animation unless we have multiple tasks
         boolean disableTapsForSplitSelect =
                 splitSelectStateController.isSplitSelectActive()
-                        && splitSelectStateController.getInitialTaskId() == getTask().key.id
+                        && splitSelectStateController.getInitialTaskId() == getFirstTask().key.id
                         && !containsMultipleTasks();
         if (disableTapsForSplitSelect) {
             return false;
@@ -795,38 +867,22 @@
         return super.dispatchTouchEvent(ev);
     }
 
-    /**
-     * @return taskId that split selection was initiated with,
-     *         {@link ActivityTaskManager#INVALID_TASK_ID} if no tasks in this TaskView are part of
-     *         split selection
-     */
-    protected int getThisTaskCurrentlyInSplitSelection() {
-        SplitSelectStateController splitSelectController =
-                getRecentsView().getSplitSelectController();
-        int initSplitTaskId = INVALID_TASK_ID;
-        for (TaskIdAttributeContainer container : getTaskIdAttributeContainers()) {
-            int taskId = container.getTask().key.id;
-            if (taskId == splitSelectController.getInitialTaskId()) {
-                initSplitTaskId = taskId;
-                break;
-            }
-        }
-        return initSplitTaskId;
-    }
-
     private void onClick(View view) {
-        if (getTask() == null) {
+        if (getFirstTask() == null) {
             Log.d("b/310064698", "onClick - task is null");
             return;
         }
         if (confirmSecondSplitSelectApp()) {
-            Log.d("b/310064698", mTask + " - onClick - split select is active");
+            Log.d("b/310064698",
+                    Arrays.toString(getTaskIds()) + " - onClick - split select is active");
             return;
         }
         RunnableList callbackList = launchTasks();
-        Log.d("b/310064698", mTask + " - onClick - callbackList: " + callbackList);
+        Log.d("b/310064698",
+                Arrays.toString(getTaskIds()) + " - onClick - callbackList: " + callbackList);
         if (callbackList != null) {
-            callbackList.add(() -> Log.d("b/310064698", mTask + " - onClick - launchCompleted"));
+            callbackList.add(() -> Log.d("b/310064698",
+                    Arrays.toString(getTaskIds()) + " - onClick - launchCompleted"));
         }
         mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo())
                 .log(LAUNCHER_TASK_LAUNCH_TAP);
@@ -834,11 +890,14 @@
 
     /**
      * @return {@code true} if user is already in split select mode and this tap was to choose the
-     *         second app. {@code false} otherwise
+     * second app. {@code false} otherwise
      */
     protected boolean confirmSecondSplitSelectApp() {
         int index = getLastSelectedChildTaskIndex();
-        TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
+        if (index >= mTaskContainers.size()) {
+            return false;
+        }
+        TaskContainer container = mTaskContainers.get(index);
         if (container != null) {
             return getRecentsView().confirmSplitSelect(this, container.getTask(),
                     container.getIconView().getDrawable(), container.getThumbnailView(),
@@ -859,22 +918,22 @@
 
     /**
      * Starts the task associated with this view and animates the startup.
+     *
      * @return CompletionStage to indicate the animation completion or null if the launch failed.
      */
     @Nullable
     public RunnableList launchTaskAnimated() {
-        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                "TaskView.launchTaskAnimated: mTask=" + mTask);
-        if (mTask != null) {
-            testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                    "TaskView.launchTaskAnimated: startActivityFromRecentsAsync");
+        if (getFirstTask() != null) {
             TestLogging.recordEvent(
-                    TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
-            ActivityOptionsWrapper opts =  mContainer.getActivityLaunchOptions(this, null);
+                    TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+                            getTaskIds()));
+            ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
             opts.options.setLaunchDisplayId(
                     getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (ActivityManagerWrapper.getInstance()
-                    .startActivityFromRecents(mTask.key, opts.options)) {
+                    .startActivityFromRecents(getFirstTask().key, opts.options)) {
+                Log.d(TAG, "launchTaskAnimated - startActivityFromRecents: " + Arrays.toString(
+                        getTaskIds()));
                 ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
                 RecentsView recentsView = getRecentsView();
                 if (recentsView.getRunningTaskViewId() != -1) {
@@ -900,6 +959,7 @@
                 return null;
             }
         } else {
+            Log.d(TAG, "launchTaskAnimated - getTask() is null" + Arrays.toString(getTaskIds()));
             return null;
         }
     }
@@ -915,20 +975,18 @@
      * Starts the task associated with this view without any animation
      */
     public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
-        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTask: mTask=" + mTask);
-        if (mTask != null) {
-            testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                    "TaskView.launchTask: startActivityFromRecentsAsync");
+        if (getFirstTask() != null) {
             TestLogging.recordEvent(
-                    TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
+                    TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+                            getTaskIds()));
 
-            final TaskRemovedDuringLaunchListener
-                    failureListener = new TaskRemovedDuringLaunchListener();
+            TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
+                    getContext().getApplicationContext());
             if (isQuickswitch) {
                 // We only listen for failures to launch in quickswitch because the during this
                 // gesture launcher is in the background state, vs other launches which are in
                 // the actual overview state
-                failureListener.register(mContainer, mTask.key.id, () -> {
+                failureListener.register(mContainer, getFirstTask().key.id, () -> {
                     notifyTaskLaunchFailed(TAG);
                     RecentsView rv = getRecentsView();
                     if (rv != null) {
@@ -950,19 +1008,18 @@
             // Indicate success once the system has indicated that the transition has started
             ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
                     MAIN_EXECUTOR.getHandler(),
-                    elapsedRealTime -> {
-                        callback.accept(true);
-                    },
-                    elapsedRealTime -> {
-                        failureListener.onTransitionFinished();
-                    });
+                    elapsedRealTime -> callback.accept(true),
+                    elapsedRealTime -> failureListener.onTransitionFinished());
             opts.setLaunchDisplayId(
                     getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (isQuickswitch) {
                 opts.setFreezeRecentTasksReordering();
             }
-            opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
-            Task.TaskKey key = mTask.key;
+            // TODO(b/334826842) add splash functionality to new TTV
+            if (!enableRefactorTaskThumbnail()) {
+                opts.setDisableStartingWindow(mTaskThumbnailViewDeprecated.shouldShowSplashView());
+            }
+            Task.TaskKey key = getFirstTask().key;
             UI_HELPER_EXECUTOR.execute(() -> {
                 if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
                     // If the call to start activity failed, then post the result immediately,
@@ -973,9 +1030,12 @@
                         callback.accept(false);
                     });
                 }
+                Log.d(TAG,
+                        "launchTask - startActivityFromRecents: " + Arrays.toString(getTaskIds()));
             });
         } else {
             callback.accept(false);
+            Log.d(TAG, "launchTask - getTask() is null" + Arrays.toString(getTaskIds()));
         }
     }
 
@@ -986,9 +1046,6 @@
     public RunnableList launchTasks() {
         RecentsView recentsView = getRecentsView();
         RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
-        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                "TaskView.launchTasks: isRunningTask=" + isRunningTask() + ", "
-                        + "remoteTargetHandles == null?" + (remoteTargetHandles == null));
         if (isRunningTask() && remoteTargetHandles != null) {
             if (!mIsClickableAsLiveTile) {
                 Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.");
@@ -1015,8 +1072,6 @@
             if (targets == null) {
                 // If the recents animation is cancelled somehow between the parent if block and
                 // here, try to launch the task as a non live tile task.
-                testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                        "TaskView.launchTasks: recents animation is cancelled");
                 RunnableList runnableList = launchTaskAnimated();
                 if (runnableList == null) {
                     Log.e(TAG, "Recents animation cancelled and cannot launch task as non-live tile"
@@ -1036,9 +1091,8 @@
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animator) {
-                    if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
-                        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                                "TaskView.launchTasks: onAnimationEnd");
+                    if (getFirstTask() != null
+                            && getFirstTask().key.displayId != getRootViewDisplayId()) {
                         launchTaskAnimated();
                     }
                     mIsClickableAsLiveTile = true;
@@ -1055,6 +1109,8 @@
                 }
             });
             anim.start();
+            Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: " + Arrays.toString(
+                    getTaskIds()));
             recentsView.onTaskLaunchedInLiveTileMode();
             return runnableList;
         } else {
@@ -1064,6 +1120,7 @@
 
     /**
      * See {@link TaskDataChanges}
+     *
      * @param visible If this task view will be visible to the user in overview or hidden
      */
     public void onTaskListVisibilityChanged(boolean visible) {
@@ -1072,10 +1129,11 @@
 
     /**
      * See {@link TaskDataChanges}
+     *
      * @param visible If this task view will be visible to the user in overview or hidden
      */
     public void onTaskListVisibilityChanged(boolean visible, @TaskDataChanges int changes) {
-        if (mTask == null) {
+        if (getFirstTask() == null) {
             return;
         }
         cancelPendingLoadTasks();
@@ -1088,12 +1146,16 @@
 
             if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
                 mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
-                        mTask, thumbnail -> {
-                            mSnapshotView.setThumbnail(mTask, thumbnail);
+                        getFirstTask(), thumbnail -> {
+                            if (!enableRefactorTaskThumbnail()) {
+                                // TODO(b/334825222) add thumbnail state
+                                mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(),
+                                        thumbnail);
+                            }
                         });
             }
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
-                mIconLoadRequest = iconCache.updateIconInBackground(mTask,
+                mIconLoadRequest = iconCache.updateIconInBackground(getFirstTask(),
                         (task) -> {
                             setIcon(mIconView, task.icon);
                             if (enableOverviewIconMenu()) {
@@ -1107,10 +1169,13 @@
             }
         } else {
             if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
-                mSnapshotView.setThumbnail(null, null);
+                if (!enableRefactorTaskThumbnail()) {
+                    // TODO(b/334825222) add thumbnail state
+                    mTaskThumbnailViewDeprecated.setThumbnail(null, null);
+                }
                 // Reset the task thumbnail reference as well (it will be fetched from the cache or
                 // reloaded next time we need it)
-                mTask.thumbnail = null;
+                getFirstTask().thumbnail = null;
             }
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                 setIcon(mIconView, null);
@@ -1154,29 +1219,33 @@
     }
 
     protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
-        TaskIdAttributeContainer menuContainer =
-                mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
+        Optional<TaskContainer> menuContainer = mTaskContainers.stream().filter(
+                container -> container.getIconView() == iconView).findAny();
+        if (menuContainer.isEmpty()) {
+            return false;
+        }
         DeviceProfile dp = mContainer.getDeviceProfile();
         if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
             ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
-            return TaskMenuView.showForTask(menuContainer,
+            return TaskMenuView.showForTask(menuContainer.get(),
                     () -> ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false));
         } else if (dp.isTablet) {
             int alignedOptionIndex = 0;
-            if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
+            if (getRecentsView().isOnGridBottomRow(menuContainer.get().getTaskView())
+                    && dp.isLandscape) {
                 if (Flags.enableGridOnlyOverview()) {
                     // With no focused task, there is less available space below the tasks, so align
                     // the arrow to the third option in the menu.
                     alignedOptionIndex = 2;
-                } else  {
+                } else {
                     // Bottom row of landscape grid aligns arrow to second option to avoid clipping
                     alignedOptionIndex = 1;
                 }
             }
-            return TaskMenuViewWithArrow.Companion.showForTask(menuContainer,
+            return TaskMenuViewWithArrow.Companion.showForTask(menuContainer.get(),
                     alignedOptionIndex);
         } else {
-            return TaskMenuView.showForTask(menuContainer);
+            return TaskMenuView.showForTask(menuContainer.get());
         }
     }
 
@@ -1215,12 +1284,16 @@
 
         // TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead
         //  of a hybrid of both margins and translations
-        LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
+        LayoutParams snapshotParams = (LayoutParams) getSnapshotView().getLayoutParams();
         snapshotParams.topMargin = thumbnailTopMargin;
-        mSnapshotView.setLayoutParams(snapshotParams);
+        getSnapshotView().setLayoutParams(snapshotParams);
 
-        mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
-        mDigitalWellBeingToast.initialize(mTask);
+        // TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
+        //  and if it's still necessary we should support that in the new TTV class.
+        if (!enableRefactorTaskThumbnail()) {
+            mTaskThumbnailViewDeprecated.getTaskOverlay().updateOrientationState(orientationState);
+        }
+        mDigitalWellBeingToast.initialize(getFirstTask());
     }
 
     /**
@@ -1231,11 +1304,6 @@
         return deviceProfile.isTablet && !isFocusedTask();
     }
 
-    /** Whether this task view represents the desktop */
-    public boolean isDesktopTask() {
-        return false;
-    }
-
     /**
      * Called to animate a smooth transition when going directly from an app into Overview (and
      * vice versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
@@ -1308,7 +1376,10 @@
         setAlpha(mStableAlpha);
         setIconScaleAndDim(1);
         setColorTint(0, 0);
-        mSnapshotView.resetViewTransforms();
+        if (!enableRefactorTaskThumbnail()) {
+            // TODO(b/335399428) add split select functionality to new TTV
+            mTaskThumbnailViewDeprecated.resetViewTransforms();
+        }
     }
 
     public void setStableAlpha(float parentAlpha) {
@@ -1321,7 +1392,12 @@
         resetPersistentViewTransforms();
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
-        mSnapshotView.setThumbnail(mTask, null);
+        // TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
+        if (enableRefactorTaskThumbnail()) {
+            notifyIsRunningTaskUpdated();
+        } else {
+            mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), null);
+        }
         setOverlayEnabled(false);
         onTaskListVisibilityChanged(false);
         mBorderEnabled = false;
@@ -1334,12 +1410,14 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (mContainer.getDeviceProfile().isTablet) {
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        if (deviceProfile.isTablet) {
             setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
-            setPivotY(mSnapshotView.getTop());
+            setPivotY(thumbnailTopMargin);
         } else {
             setPivotX((right - left) * 0.5f);
-            setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+            setPivotY(thumbnailTopMargin + (getHeight() - thumbnailTopMargin) * 0.5f);
         }
         SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
         setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
@@ -1385,6 +1463,9 @@
         scale *= mDismissScale;
         setScaleX(scale);
         setScaleY(scale);
+        if (enableRefactorTaskThumbnail()) {
+            mTaskViewData.getScale().setValue(scale);
+        }
         updateSnapshotRadius();
     }
 
@@ -1407,11 +1488,17 @@
     }
 
     protected void applyThumbnailSplashAlpha() {
-        mSnapshotView.setSplashAlpha(mTaskThumbnailSplashAlpha);
+        if (!enableRefactorTaskThumbnail()) {
+            // TODO(b/334826842) add splash functionality to new TTV
+            mTaskThumbnailViewDeprecated.setSplashAlpha(mTaskThumbnailSplashAlpha);
+        }
     }
 
     protected void refreshTaskThumbnailSplash() {
-        mSnapshotView.refreshSplashView();
+        if (!enableRefactorTaskThumbnail()) {
+            // TODO(b/334826842) add splash functionality to new TTV
+            mTaskThumbnailViewDeprecated.refreshSplashView();
+        }
     }
 
     private void setSplitSelectTranslationX(float x) {
@@ -1609,10 +1696,7 @@
                         getContext().getText(R.string.accessibility_close)));
 
         final Context context = getContext();
-        for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
-            if (taskContainer == null) {
-                continue;
-            }
+        for (TaskContainer taskContainer : mTaskContainers) {
             for (SystemShortcut s : TraceHelper.allowIpcs(
                     "TV.a11yInfo", () -> getEnabledShortcuts(this, taskContainer))) {
                 info.addAction(s.createAccessibilityAction(context));
@@ -1647,10 +1731,7 @@
             return true;
         }
 
-        for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
-            if (taskContainer == null) {
-                continue;
-            }
+        for (TaskContainer taskContainer : mTaskContainers) {
             for (SystemShortcut s : getEnabledShortcuts(this,
                     taskContainer)) {
                 if (s.hasHandlerForAction(action)) {
@@ -1664,8 +1745,8 @@
     }
 
     @Nullable
-    public RecentsView getRecentsView() {
-        return (RecentsView) getParent();
+    public RecentsView<?, ?> getRecentsView() {
+        return (RecentsView<?, ?>) getParent();
     }
 
     RecentsPagedOrientationHandler getPagedOrientationHandler() {
@@ -1674,8 +1755,9 @@
 
     private void notifyTaskLaunchFailed(String tag) {
         String msg = "Failed to launch task";
-        if (mTask != null) {
-            msg += " (task=" + mTask.key.baseIntent + " userId=" + mTask.key.userId + ")";
+        if (getFirstTask() != null) {
+            msg += " (task=" + getFirstTask().key.baseIntent + " userId="
+                    + getFirstTask().key.userId + ")";
         }
         Log.w(tag, msg);
         Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
@@ -1690,7 +1772,8 @@
         progress = Utilities.boundToRange(progress, 0, 1);
         mFullscreenProgress = progress;
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
-        mSnapshotView.getTaskOverlay().setFullscreenProgress(progress);
+        mTaskThumbnailViewDeprecated.getTaskOverlay().setFullscreenProgress(progress);
+
         RecentsView recentsView = mContainer.getOverviewPanel();
         // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
         // oversized and banner would look disproportionately large.
@@ -1703,7 +1786,7 @@
 
     protected void updateSnapshotRadius() {
         updateCurrentFullscreenParams();
-        mSnapshotView.setFullscreenParams(mCurrentFullscreenParams);
+        mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
     }
 
     void updateCurrentFullscreenParams() {
@@ -1714,8 +1797,8 @@
         if (getRecentsView() == null) {
             return;
         }
-        fullscreenParams.setProgress(mFullscreenProgress, getRecentsView().getScaleX(),
-                getScaleX());
+        fullscreenParams.setProgress(
+                mFullscreenProgress, getRecentsView().getScaleX(), getScaleX());
     }
 
     /**
@@ -1816,7 +1899,11 @@
     }
 
     public void setOverlayEnabled(boolean overlayEnabled) {
-        mSnapshotView.setOverlayEnabled(overlayEnabled);
+        // TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
+        //  and if it's still necessary we should support that in the new TTV class.
+        if (!enableRefactorTaskThumbnail()) {
+            mTaskThumbnailViewDeprecated.setOverlayEnabled(overlayEnabled);
+        }
     }
 
     public void initiateSplitSelect(SplitPositionOption splitPositionOption) {
@@ -1828,20 +1915,23 @@
      * Set a color tint on the snapshot and supporting views.
      */
     public void setColorTint(float amount, int tintColor) {
-        mSnapshotView.setDimAlpha(amount);
+        if (!enableRefactorTaskThumbnail()) {
+            // TODO(b/334832108) Add scrim to new TTV
+            mTaskThumbnailViewDeprecated.setDimAlpha(amount);
+        }
         mIconView.setIconColorTint(tintColor, amount);
         mDigitalWellBeingToast.setBannerColorTint(tintColor, amount);
     }
 
 
     private int getRootViewDisplayId() {
-        Display  display = getRootView().getDisplay();
+        Display display = getRootView().getDisplay();
         return display != null ? display.getDisplayId() : DEFAULT_DISPLAY;
     }
 
     /**
-     *  Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
-     *  IconView is unaffected.
+     * Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
+     * IconView is unaffected.
      *
      * @param taskId is only used when setting visibility to a non-{@link View#VISIBLE} value
      */
@@ -1854,10 +1944,14 @@
         }
     }
 
+    private View getSnapshotView() {
+        return enableRefactorTaskThumbnail() ? mTaskThumbnailView : mTaskThumbnailViewDeprecated;
+    }
+
     /**
      * We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
      */
-    public static class FullscreenDrawParams {
+    public static class FullscreenDrawParams implements SafeCloseable {
 
         private float mCornerRadius;
         private float mWindowCornerRadius;
@@ -1892,28 +1986,38 @@
                     Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
                             / parentScale / taskViewScale;
         }
+
+        @Override
+        public void close() {
+        }
     }
 
-    public class TaskIdAttributeContainer {
-        private final TaskThumbnailView mThumbnailView;
+    /**
+     * Holder for all Task dependent information.
+     */
+    public class TaskContainer {
+        private final TaskThumbnailViewDeprecated mThumbnailView;
         private final Task mTask;
         private final TaskViewIcon mIconView;
         /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
         private @SplitConfigurationOptions.StagePosition int mStagePosition;
         @IdRes
         private final int mA11yNodeId;
+        private final DigitalWellBeingToast mDigitalWellBeingToast;
 
-        public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
-                TaskViewIcon iconView, int stagePosition) {
+        public TaskContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
+                TaskViewIcon iconView, int stagePosition,
+                DigitalWellBeingToast digitalWellBeingToast) {
             this.mTask = task;
             this.mThumbnailView = thumbnailView;
             this.mIconView = iconView;
             this.mStagePosition = stagePosition;
             this.mA11yNodeId = (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) ?
                     R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
+            this.mDigitalWellBeingToast = digitalWellBeingToast;
         }
 
-        public TaskThumbnailView getThumbnailView() {
+        public TaskThumbnailViewDeprecated getThumbnailView() {
             return mThumbnailView;
         }
 
@@ -1944,5 +2048,9 @@
         public int getA11yNodeId() {
             return mA11yNodeId;
         }
+
+        public DigitalWellBeingToast getDigitalWellBeingToast() {
+            return mDigitalWellBeingToast;
+        }
     }
 }
diff --git a/quickstep/tests/OWNERS b/quickstep/tests/OWNERS
index c271803..02e8ebc 100644
--- a/quickstep/tests/OWNERS
+++ b/quickstep/tests/OWNERS
@@ -2,4 +2,3 @@
 sunnygoyal@google.com
 winsonc@google.com
 hyunyoungs@google.com
-mateuszc@google.com
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 58be345..0f06d98 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -12,10 +12,10 @@
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
@@ -31,7 +31,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.quickstep.OverviewCommandHelper;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TouchInteractionService;
 import com.android.quickstep.util.AssistUtils;
@@ -52,8 +52,6 @@
     @Mock
     TouchInteractionService mockService;
     @Mock
-    OverviewCommandHelper mockCommandHelper;
-    @Mock
     Handler mockHandler;
     @Mock
     AssistUtils mockAssistUtils;
@@ -68,13 +66,26 @@
     @Mock
     View mockView;
 
+    private int mHomePressCount;
+    private int mOverviewToggleCount;
+    private final TaskbarNavButtonCallbacks mCallbacks = new TaskbarNavButtonCallbacks() {
+        @Override
+        public void onNavigateHome() {
+            mHomePressCount++;
+        }
+
+        @Override
+        public void onToggleOverview() {
+            mOverviewToggleCount++;
+        }
+    };
+
     private TaskbarNavButtonController mNavButtonController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
-        when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
         when(mockService.getApplicationContext())
                 .thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
                         .getApplicationContext());
@@ -82,8 +93,12 @@
         when(mockTaskbarControllers.getTaskbarActivityContext())
                 .thenReturn(mockTaskbarActivityContext);
         doReturn(mockStatsLogManager).when(mockTaskbarActivityContext).getStatsLogManager();
-        mNavButtonController = new TaskbarNavButtonController(mockService,
-                mockSystemUiProxy, mockHandler, mockAssistUtils);
+        mNavButtonController = new TaskbarNavButtonController(
+                mockService,
+                mCallbacks,
+                mockSystemUiProxy,
+                mockHandler,
+                mockAssistUtils);
     }
 
     @Test
@@ -154,20 +169,20 @@
     @Test
     public void testPressHome() {
         mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
-        verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
+        assertThat(mHomePressCount).isEqualTo(1);
     }
 
     @Test
     public void testPressRecents() {
         mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
-        verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
+        assertThat(mOverviewToggleCount).isEqualTo(1);
     }
 
     @Test
-    public void testPressRecentsWithScreenPinned() {
+    public void testPressRecentsWithScreenPinned_noNavigationToOverview() {
         mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
         mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
-        verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
+        assertThat(mOverviewToggleCount).isEqualTo(0);
     }
 
     @Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/OWNERS
new file mode 100644
index 0000000..3f947a0
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -0,0 +1,5 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
+
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 b478efa..2bcfa3f 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
@@ -16,19 +16,14 @@
 
 package com.android.launcher3.taskbar.bubbles.animation
 
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.AnimatorSet
 import android.content.Context
 import android.graphics.Color
 import android.graphics.Path
 import android.graphics.drawable.ColorDrawable
 import android.view.LayoutInflater
-import android.view.View.INVISIBLE
+import android.view.View
 import android.view.View.VISIBLE
 import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
-import androidx.core.animation.doOnEnd
 import androidx.core.graphics.drawable.toBitmap
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.test.core.app.ApplicationProvider
@@ -42,14 +37,13 @@
 import com.android.launcher3.taskbar.bubbles.BubbleStashController
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.animation.PhysicsAnimator
 import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
 import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 import org.junit.Before
-import org.junit.ClassRule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
@@ -59,23 +53,333 @@
 class BubbleBarViewAnimatorTest {
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
-    private val animatorScheduler = TestBubbleBarViewAnimatorScheduler()
-
-    companion object {
-        @JvmField @ClassRule val animatorTestRule = AnimatorTestRule()
-    }
+    private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler
+    private lateinit var overflowView: BubbleView
+    private lateinit var bubbleView: BubbleView
+    private lateinit var bubble: BubbleBarBubble
+    private lateinit var bubbleBarView: BubbleBarView
+    private lateinit var bubbleStashController: BubbleStashController
 
     @Before
     fun setUp() {
+        animatorScheduler = TestBubbleBarViewAnimatorScheduler()
         PhysicsAnimatorTestUtils.prepareForTest()
     }
 
     @Test
     fun animateBubbleInForStashed() {
-        lateinit var overflowView: BubbleView
-        lateinit var bubbleView: BubbleView
-        lateinit var bubble: BubbleBarBubble
-        val bubbleBarView = BubbleBarView(context)
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // let the animation start and wait for it to complete
+        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(bubbleBarView.isAnimatingNewBubble).isTrue()
+
+        // execute the hide bubble animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+        // let the animation start and wait for it to complete
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(handle.alpha).isEqualTo(1)
+        assertThat(handle.translationY).isEqualTo(0)
+        assertThat(bubbleBarView.alpha).isEqualTo(0)
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        verify(bubbleStashController).stashBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_tapAnimatingBubble() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // let the animation start and wait for it to complete
+        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(bubbleBarView.isAnimatingNewBubble).isTrue()
+
+        verify(bubbleStashController).updateTaskbarTouchRegion()
+
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        animator.onBubbleClickedWhileAnimating()
+
+        assertThat(animatorScheduler.delayedBlock).isNull()
+        assertThat(bubbleBarView.alpha).isEqualTo(1)
+        assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_touchTaskbarArea_whileShowing() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+        assertThat(handleAnimator.isRunning()).isTrue()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        // verify the hide bubble animation is pending
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.onStashStateChangingWhileAnimating()
+        }
+
+        // verify that the hide animation was canceled
+        assertThat(animatorScheduler.delayedBlock).isNull()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
+
+        // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
+        // again
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        assertThat(handleAnimator.isRunning()).isFalse()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_touchTaskbarArea_whileHiding() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // let the animation start and wait for it to complete
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        // execute the hide bubble animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+        // wait for the hide animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        assertThat(handleAnimator.isRunning()).isTrue()
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.onStashStateChangingWhileAnimating()
+        }
+
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
+
+        // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
+        // again
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        assertThat(handleAnimator.isRunning()).isFalse()
+    }
+
+    @Test
+    fun animateBubbleInForStashed_showAnimationCanceled() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // wait for the animation to start
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+        assertThat(handleAnimator.isRunning()).isTrue()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+        handleAnimator.cancel()
+        assertThat(handleAnimator.isRunning()).isFalse()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(animatorScheduler.delayedBlock).isNull()
+    }
+
+    @Test
+    fun animateToInitialState_inApp() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(barAnimator.isRunning()).isFalse()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        assertThat(bubbleBarView.alpha).isEqualTo(1)
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+        assertThat(bubbleBarView.alpha).isEqualTo(0)
+        assertThat(handle.translationY).isEqualTo(0)
+        assertThat(handle.alpha).isEqualTo(1)
+
+        verify(bubbleStashController).stashBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateToInitialState_inApp_autoExpanding() {
+        setUpBubbleBar()
+        setUpBubbleStashController()
+        whenever(bubbleStashController.bubbleBarTranslationY)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(barAnimator.isRunning()).isFalse()
+        assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+        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)
+
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    @Test
+    fun animateToInitialState_inHome() {
+        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.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(barAnimator.isRunning()).isFalse()
+        assertThat(bubbleBarView.isAnimatingNewBubble).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(bubbleBarView.alpha).isEqualTo(1)
+        assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+        verify(bubbleStashController).showBubbleBarImmediate()
+    }
+
+    private fun setUpBubbleBar() {
+        bubbleBarView = BubbleBarView(context)
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
             val inflater = LayoutInflater.from(context)
@@ -95,95 +399,41 @@
             bubbleBarView.addView(bubbleView)
         }
         InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-
-        val bubbleStashController = mock<BubbleStashController>()
-        whenever(bubbleStashController.isStashed).thenReturn(true)
-
-        val semaphore = Semaphore(0)
-        val hideHandleAnimator = AnimatorSet()
-        hideHandleAnimator.duration = 0
-        whenever(bubbleStashController.buildHideHandleAnimationForNewBubble())
-            .thenReturn(hideHandleAnimator)
-        // add an end listener to the hide handle animation. we add it when the animation starts
-        // to ensure that it gets called after all other end listeners.
-        hideHandleAnimator.doOnStart { hideHandleAnimator.doOnEnd { semaphore.release() } }
-
-        val animator =
-            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
-
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animator.animateBubbleInForStashed(bubble)
-        }
-
-        // wait for the stash handle animation to complete
-        assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
-        // stash handle animation finished. verify that the stash handle is now hidden
-        verify(bubbleStashController).setStashAlpha(0f)
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-
-        assertThat(overflowView.visibility).isEqualTo(INVISIBLE)
-        assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
-        assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
-
-        // wait for the show bubble animation to complete
-        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(
-            DynamicAnimation.ALPHA,
-            DynamicAnimation.TRANSLATION_Y,
-            DynamicAnimation.SCALE_Y,
-        )
-
-        assertThat(bubbleView.alpha).isEqualTo(1)
-        assertThat(bubbleView.translationY).isEqualTo(-50)
-        assertThat(bubbleView.scaleY).isEqualTo(1)
-
-        val showHandleAnimator = AnimatorSet()
-        showHandleAnimator.duration = 0
-        whenever(bubbleStashController.buildShowHandleAnimationForNewBubble())
-            .thenReturn(showHandleAnimator)
-        var showHandleAnimationStarted = false
-        showHandleAnimator.doOnStart { showHandleAnimationStarted = true }
-
-        // execute the hide bubble animation
-        assertThat(animatorScheduler.delayedBlock).isNotNull()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
-        // finish the hide bubble animation
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animatorTestRule.advanceTimeBy(250)
-        }
-
-        assertThat(showHandleAnimationStarted).isTrue()
-
-        assertThat(bubbleView.alpha).isEqualTo(1)
-        assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
-        assertThat(bubbleView.translationY).isEqualTo(0)
-        assertThat(bubbleBarView.alpha).isEqualTo(0)
-        assertThat(overflowView.alpha).isEqualTo(1)
-        assertThat(overflowView.visibility).isEqualTo(VISIBLE)
     }
 
-    private fun AnimatorSet.doOnStart(onStart: () -> Unit) {
-        addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationStart(animator: Animator) {
-                    onStart()
-                }
-            }
-        )
+    private fun setUpBubbleStashController() {
+        bubbleStashController = mock<BubbleStashController>()
+        whenever(bubbleStashController.isStashed).thenReturn(true)
+        whenever(bubbleStashController.diffBetweenHandleAndBarCenters)
+            .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS)
+        whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation)
+            .thenReturn(HANDLE_TRANSLATION)
+        whenever(bubbleStashController.bubbleBarTranslationYForTaskbar)
+            .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
     }
 
     private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler {
 
-        var delayedBlock: (() -> Unit)? = null
+        var delayedBlock: Runnable? = null
             private set
 
-        override fun post(block: () -> Unit) {
-            block.invoke()
+        override fun post(block: Runnable) {
+            block.run()
         }
 
-        override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+        override fun postDelayed(delayMillis: Long, block: Runnable) {
             check(delayedBlock == null) { "there is already a pending block waiting to run" }
             delayedBlock = block
         }
+
+        override fun cancel(block: Runnable) {
+            check(delayedBlock == block) { "the pending block does not match the canceled block" }
+            delayedBlock = null
+        }
     }
 }
+
+private const val DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS = -20f
+private const val HANDLE_TRANSLATION = -30f
+private const val BAR_TRANSLATION_Y_FOR_TASKBAR = -50f
+private const val BAR_TRANSLATION_Y_FOR_HOTSEAT = -40f
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index c327166..c8f7946 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -17,8 +17,6 @@
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
-import com.android.systemui.shared.rotation.RotationButton
-import java.lang.IllegalStateException
 import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
@@ -39,10 +37,9 @@
     private val mockRecentsButton: ImageView = mock()
     private val mockHomeButton: ImageView = mock()
     private val mockImeSwitcher: ImageView = mock()
-    private val mockRotationButton: RotationButton = mock()
     private val mockA11yButton: ImageView = mock()
     private val mockSpace: Space = mock()
-    private val mockConfiguration: Configuration = mock();
+    private val mockConfiguration: Configuration = mock()
 
     private var surfaceRotation = Surface.ROTATION_0
 
@@ -210,7 +207,6 @@
             phoneMode = phoneMode,
             surfaceRotation = surfaceRotation,
             imeSwitcher = mockImeSwitcher,
-            rotationButton = mockRotationButton,
             a11yButton = mockA11yButton,
             space = mockSpace,
         )
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
new file mode 100644
index 0000000..efd7bec
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.viewmodel.TaskViewData
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TaskThumbnailViewModelTest {
+    private val recentsViewData = RecentsViewData()
+    private val taskViewData = TaskViewData()
+    private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
+
+    @Test
+    fun initialStateIsUninitialized() = runTest {
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+    }
+
+    @Test
+    fun bindRunningTask_thenStateIs_LiveTile() = runTest {
+        val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+        systemUnderTest.bind(taskThumbnail)
+
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+    }
+
+    @Test
+    fun setRecentsFullscreenProgress_thenProgressIsPassedThrough() = runTest {
+        recentsViewData.fullscreenProgress.value = 0.5f
+
+        assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.5f)
+
+        recentsViewData.fullscreenProgress.value = 0.6f
+
+        assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.6f)
+    }
+
+    @Test
+    fun setAncestorScales_thenScaleIsCalculated() = runTest {
+        recentsViewData.scale.value = 0.5f
+        taskViewData.scale.value = 0.6f
+
+        assertThat(systemUnderTest.inheritedScale.first()).isEqualTo(0.3f)
+    }
+
+    @Test
+    fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
+        // TODO(b/334825222): Change the expectation here when snapshot state is implemented
+        val task = Task()
+        val runningTask = TaskThumbnail(task, isRunning = true)
+        val stoppedTask = TaskThumbnail(task, isRunning = false)
+        systemUnderTest.bind(runningTask)
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+
+        systemUnderTest.bind(stoppedTask)
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 9fa4b79..72cfd92 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.util.window.CachedDisplayInfo;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.SurfaceTransaction.MockProperties;
 
 import org.hamcrest.Description;
@@ -160,7 +159,6 @@
         void verifyNoTransforms() {
             LauncherModelHelper helper = new LauncherModelHelper();
             try {
-                helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
                 int rotation = mDisplaySize.x > mDisplaySize.y
                         ? Surface.ROTATION_90 : Surface.ROTATION_0;
                 CachedDisplayInfo cdi = new CachedDisplayInfo(mDisplaySize, rotation);
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
new file mode 100644
index 0000000..4fafde8
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidTestingRunner::class)
+class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+
+    @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var mockRecentsModel: RecentsModel
+    @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
+
+    private var nextTaskId: Int = 500
+
+    private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
+    private lateinit var userHandle: UserHandle
+
+    @Before
+    fun setUp() {
+        super.setup()
+        userHandle = Process.myUserHandle()
+        taskbarRunningAppsController =
+            DesktopTaskbarRunningAppsController(mockRecentsModel) {
+                mockDesktopVisibilityController
+            }
+        taskbarRunningAppsController.init(taskbarControllers)
+        taskbarRunningAppsController.setApps(
+            ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
+        )
+    }
+
+    @Test
+    fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
+        setInDesktopMode(false)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+
+        assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+            .isEqualTo(hotseatItems.toTypedArray())
+    }
+
+    @Test
+    fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() {
+        setInDesktopMode(false)
+        val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
+        val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps()
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(hotseatPackages)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
+        setInDesktopMode(true)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+
+        assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+            .isEqualTo(hotseatItems.toTypedArray())
+    }
+
+    @Test
+    fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() {
+        setInDesktopMode(true)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps()
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        val expectedPackages =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+            )
+        assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() {
+        setInDesktopMode(true)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+        val runningTasks =
+            createDesktopTasksFromPackageNames(
+                listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+            )
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps()
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        val expectedPackages =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+            )
+        assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+    }
+
+    @Test
+    fun getRunningApps_notInDesktopMode_returnsEmptySet() {
+        setInDesktopMode(false)
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps()
+
+        assertThat(taskbarRunningAppsController.runningApps).isEqualTo(emptySet<String>())
+    }
+
+    @Test
+    fun getRunningApps_inDesktopMode_returnsRunningApps() {
+        setInDesktopMode(true)
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps()
+
+        assertThat(taskbarRunningAppsController.runningApps)
+            .isEqualTo(setOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+    }
+
+    private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
+        return packageNames.map { createTestAppInfo(packageName = it) }
+    }
+
+    private fun createDesktopTasksFromPackageNames(
+        packageNames: List<String>
+    ): ArrayList<RunningTaskInfo> {
+        return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
+    }
+
+    private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+        return RunningTaskInfo().apply {
+            taskId = nextTaskId++
+            configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+            realActivity = ComponentName(packageName, "TestActivity")
+        }
+    }
+
+    private fun createTestAppInfo(
+        packageName: String = "testPackageName",
+        className: String = "testClassName"
+    ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
+
+    private fun setInDesktopMode(inDesktopMode: Boolean) {
+        whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
+    }
+
+    private companion object {
+        const val HOTSEAT_PACKAGE_1 = "hotseat1"
+        const val HOTSEAT_PACKAGE_2 = "hotseat2"
+        const val RUNNING_APP_PACKAGE_1 = "running1"
+        const val RUNNING_APP_PACKAGE_2 = "running2"
+        const val RUNNING_APP_PACKAGE_3 = "running3"
+        val ALL_APP_PACKAGES =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+                RUNNING_APP_PACKAGE_3,
+            )
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 7dabbca..d59aafb 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -19,9 +19,11 @@
 import android.content.ComponentName
 import android.content.Intent
 import android.platform.test.flag.junit.SetFlagsRule
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.launcher3.AbstractFloatingView
 import com.android.launcher3.AbstractFloatingViewHelper
-import com.android.launcher3.Launcher
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent
 import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -33,6 +35,8 @@
 import com.android.systemui.shared.recents.model.Task.TaskKey
 import com.android.window.flags.Flags
 import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.kotlin.any
@@ -40,6 +44,7 @@
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
 
 /** Test for DesktopSystemShortcut */
 class DesktopSystemShortcutTest {
@@ -56,8 +61,26 @@
     private val factory: TaskShortcutFactory =
         DesktopSystemShortcut.createFactory(abstractFloatingViewHelper)
 
+    private lateinit var mockitoSession: StaticMockitoSession
+
+    @Before
+    fun setUp() {
+        mockitoSession =
+            mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .spyStatic(DesktopModeStatus::class.java)
+                .startMocking()
+        doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+    }
+
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+    }
+
     @Test
-    fun createDesktopTaskShortcutFactory_featureOff() {
+    fun createDesktopTaskShortcutFactory_desktopModeDisabled() {
         setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
 
         val task =
@@ -65,11 +88,12 @@
                 isDockable = true
             }
         val taskContainer =
-            taskView.TaskIdAttributeContainer(
+            taskView.TaskContainer(
                 task,
                 null,
                 null,
-                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                null
             )
 
         val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -77,6 +101,51 @@
     }
 
     @Test
+    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                null
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNull()
+    }
+
+    @Test
+    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+        doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                null
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNotNull()
+    }
+
+    @Test
     fun createDesktopTaskShortcutFactory_undockable() {
         setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
 
@@ -85,11 +154,12 @@
                 isDockable = false
             }
         val taskContainer =
-            taskView.TaskIdAttributeContainer(
+            taskView.TaskContainer(
                 task,
                 null,
                 null,
-                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                null
             )
 
         val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -105,11 +175,12 @@
                 isDockable = true
             }
         val taskContainer =
-            taskView.TaskIdAttributeContainer(
+            taskView.TaskContainer(
                 task,
                 null,
                 null,
-                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+                null
             )
 
         whenever(launcher.getOverviewPanel<LauncherRecentsView>()).thenReturn(recentsView)
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 5b16c0f..2858929 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
 import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
-import static com.android.launcher3.testing.shared.TestProtocol.UPDATE_OVERVIEW_TARGETS_RUNNING_LATE;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_BROADCAST_TIMEOUT_SECS;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
@@ -43,7 +42,6 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.RemoteException;
-import android.util.Log;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -116,8 +114,6 @@
         mDevice.setOrientationNatural();
         mLauncher = AbstractLauncherUiTest.createLauncherInstrumentation();
         mLauncher.enableDebugTracing();
-        // b/143488140
-        //mLauncher.enableCheckEventsForSuccessfulGestures();
 
         if (TestHelpers.isInLauncherProcess()) {
             Utilities.enableRunningInTestHarnessForTests();
@@ -133,13 +129,6 @@
                         getLauncherCommand(mOtherLauncherActivity));
                 updateHandler.mChangeCounter
                         .await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
-                Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                        "AFTER AWAIT: mObserver home intent package name="
-                                + updateHandler.mObserver.getHomeIntent()
-                                        .getComponent().getPackageName());
-                Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                        "AFTER AWAIT: mOtherLauncherActivity package name="
-                                + mOtherLauncherActivity.packageName);
                 try {
                     base.evaluate();
                 } finally {
@@ -147,7 +136,6 @@
                     TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
                     UiDevice.getInstance(getInstrumentation()).executeShellCommand(
                             getLauncherCommand(getLauncherInMyProcess()));
-                    // b/143488140
                     pressHomeAndWaitForOverviewClose();
                 }
             }
@@ -191,8 +179,6 @@
         }
     }
 
-    // b/143488140
-    //@NavigationModeSwitch
     @Test
     public void goToOverviewFromHome() {
         mDevice.pressHome();
@@ -261,10 +247,7 @@
                 DEFAULT_UI_TIMEOUT, mLauncher);
     }
 
-    // b/143488140
-    //@NavigationModeSwitch
     @Test
-    @ScreenRecordRule.ScreenRecord // b/321775748
     public void testOverview() throws IOException {
         startAppFast(getAppPackageName());
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@@ -348,25 +331,12 @@
             mRads = new RecentsAnimationDeviceState(ctx);
             mObserver = new OverviewComponentObserver(ctx, mRads);
             mChangeCounter = new CountDownLatch(1);
-            Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                    "OverviewUpdateHandler(Constructor): mObserver home intent package name="
-                            + mObserver.getHomeIntent().getComponent().getPackageName());
-            Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                    "OverviewUpdateHandler(Constructor): mOtherLauncherActivity package name="
-                            + mOtherLauncherActivity.packageName);
             if (mObserver.getHomeIntent().getComponent()
                     .getPackageName().equals(mOtherLauncherActivity.packageName)) {
                 // Home already same
                 mChangeCounter.countDown();
             } else {
-                mObserver.setOverviewChangeListener(b -> {
-                    Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                            "OverviewChangeListener(Callback): isHomeAndOverviewSame=" + b);
-                    Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
-                            "OverviewChangeListener(Callback): mObserver home intent package name="
-                                    + mObserver.getHomeIntent().getComponent().getPackageName());
-                    mChangeCounter.countDown();
-                });
+                mObserver.setOverviewChangeListener(b -> mChangeCounter.countDown());
             }
         }
 
diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
index b1ba4c6..a388510 100644
--- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
@@ -42,6 +42,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(70)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1445)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(580)
@@ -64,6 +66,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(4)
         assertThat(dp.hotseatBorderSpace).isEqualTo(40)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1080)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(550)
@@ -85,6 +89,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(54)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1468)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(231)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(759)
@@ -100,22 +106,21 @@
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
-        inv?.apply {
-            hotseatColumnSpan = IntArray(4) { 4 }
-            inlineQsb = BooleanArray(4) { false }
-        }
+        inv?.apply { inlineQsb = BooleanArray(4) { false } }
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(100)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1975)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(1040)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1223)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1965)
     }
 
     /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@@ -128,13 +133,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(36)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(34)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(4)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1179)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(864)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(696)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(876)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(694)
 
         assertThat(dp.isQsbInline).isTrue()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(528)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(542)
     }
 
     /**
@@ -151,6 +158,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(5)
         assertThat(dp.hotseatBorderSpace).isEqualTo(36)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(4)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1095)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(816)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(700)
@@ -158,4 +167,23 @@
         assertThat(dp.isQsbInline).isTrue()
         assertThat(dp.hotseatQsbWidth).isEqualTo(480)
     }
+
+    @Test
+    fun increase_span_when_space_between_icons_is_less_than_minimum() {
+        initializeVarsForTwoPanel(isGestureMode = false, isLandscape = false, rows = 5, cols = 5)
+        val dp = newDP()
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(600)
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(48)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(8)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1383)
+
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(126)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(652)
+
+        assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1372)
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index df88726..094fd4c 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -205,11 +205,10 @@
             boolean condition, Description description) {
         launcher.checkForAnomaly(true, true);
         if (!condition) {
-            final AssertionError assertionError = new AssertionError(message);
             if (description != null) {
-                FailureWatcher.onError(launcher, description, assertionError);
+                FailureWatcher.onError(launcher, description);
             }
-            throw assertionError;
+            throw new AssertionError(message);
         }
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 4aa7cb0..37ab131 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -86,8 +86,8 @@
         final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
 
         return getFromLauncher(launcher -> {
-            assertTrue("Latest task is not Calculator",
-                    CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
+            assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(
+                    task.getFirstTask().getTopComponent().getPackageName()));
             return task.getDigitalWellBeingToast();
         });
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 0c143b4..69a7664 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -21,16 +21,21 @@
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import android.util.Log;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
+import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.PrivateSpaceContainer;
+import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 
 import org.junit.After;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -42,7 +47,9 @@
 public class TaplPrivateSpaceTest extends AbstractQuickStepTest {
 
     private int mProfileUserId;
-    private boolean mPrivateProfileSetupSuccessful;
+
+    private static final String PRIVATE_PROFILE_NAME = "LauncherPrivateProfile";
+    private static final String INSTALLED_APP_NAME = "Aardwolf";
     private static final String TAG = "TaplPrivateSpaceTest";
 
     @Override
@@ -51,8 +58,6 @@
         initialize(this);
 
         createAndStartPrivateProfileUser();
-        assumeTrue("Private Profile Setup not successful, aborting",
-                mPrivateProfileSetupSuccessful);
 
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -71,7 +76,7 @@
 
     private void createAndStartPrivateProfileUser() {
         String createUserOutput = executeShellCommand("pm create-user --profileOf 0 --user-type "
-                + "android.os.usertype.profile.PRIVATE LauncherPrivateProfile");
+                + "android.os.usertype.profile.PRIVATE " + PRIVATE_PROFILE_NAME);
         updatePrivateProfileSetupSuccessful("pm create-user", createUserOutput);
         String[] tokens = createUserOutput.split("\\s+");
         mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
@@ -85,21 +90,133 @@
 
     @After
     public void removePrivateProfile() {
-        String output = executeShellCommand("pm remove-user " + mProfileUserId);
-        updateProfileRemovalSuccessful("pm remove-user", output);
-        waitForPrivateSpaceRemoval();
+        String userListOutput = executeShellCommand("pm list users");
+        if (isPrivateProfilePresent("pm list users", userListOutput)) {
+            String output = executeShellCommand("pm remove-user " + mProfileUserId);
+            updateProfileRemovalSuccessful("pm remove-user", output);
+            waitForPrivateSpaceRemoval();
+        }
     }
 
     @Test
     public void testPrivateSpaceContainerIsPresent() {
-        assumeTrue(mPrivateProfileSetupSuccessful);
         // Scroll to the bottom of All Apps
         executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
-        waitForResumed("Launcher internal state is still Background");
+        // Freeze All Apps
+        HomeAllApps homeAllApps = mLauncher.getAllApps();
+        homeAllApps.freeze();
 
-        // Verify Unlocked View elements are present.
-        assertNotNull("Private Space Unlocked View not found, or is not correct",
-                mLauncher.getAllApps().getPrivateSpaceUnlockedView());
+        try {
+            // Verify Unlocked View elements are present.
+            assertNotNull("Private Space Unlocked View not found, or is not correct",
+                    homeAllApps.getPrivateSpaceUnlockedView());
+        } finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+    }
+
+    @Test
+    @ScreenRecordRule.ScreenRecord // b/334946529
+    public void testUserInstalledAppIsShownAboveDivider() throws IOException {
+        // Ensure that the App is not installed in main user otherwise, it may not be found in
+        // PS container.
+        TestUtil.uninstallDummyApp();
+        // Install the app in Private Profile
+        TestUtil.installDummyAppForUser(mProfileUserId);
+        waitForLauncherUIUpdate();
+        // Scroll to the bottom of All Apps
+        executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+        // Freeze All Apps
+        HomeAllApps homeAllApps = mLauncher.getAllApps();
+        homeAllApps.freeze();
+
+        try {
+            // Verify the Installed App is displayed in correct position.
+            PrivateSpaceContainer psContainer = homeAllApps.getPrivateSpaceUnlockedView();
+            psContainer.verifyInstalledAppIsPresent(INSTALLED_APP_NAME);
+        } finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+    }
+
+    @Test
+    @ScreenRecordRule.ScreenRecord // b/334946529
+    public void testPrivateSpaceAppLongPressUninstallMenu() throws IOException {
+        // Ensure that the App is not installed in main user otherwise, it may not be found in
+        // PS container.
+        TestUtil.uninstallDummyApp();
+        // Install the app in Private Profile
+        TestUtil.installDummyAppForUser(mProfileUserId);
+        waitForLauncherUIUpdate();
+        // Scroll to the bottom of All Apps
+        executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+        // Freeze All Apps
+        HomeAllApps homeAllApps = mLauncher.getAllApps();
+        homeAllApps.freeze();
+
+        try {
+            // Get the "uninstall" menu item.
+            homeAllApps.getAppIcon(INSTALLED_APP_NAME).openMenu().getMenuItem("Uninstall");
+        } finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+    }
+
+    @Test
+    @ScreenRecordRule.ScreenRecord // b/334946529
+    @Ignore("b/339179262")
+    public void testPrivateSpaceLockingBehaviour() throws IOException {
+        // Scroll to the bottom of All Apps
+        executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+        HomeAllApps homeAllApps = mLauncher.getAllApps();
+
+        // Disable Private Space
+        togglePrivateSpace(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+
+        homeAllApps.freeze();
+        try {
+            // Verify Locked View elements are present.
+            homeAllApps.getPrivateSpaceLockedView();
+        } finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+
+        // Enable Private Space
+        togglePrivateSpace(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+
+        homeAllApps.freeze();
+        try {
+            // Verify UnLocked View elements are present.
+            homeAllApps.getPrivateSpaceUnlockedView();
+        } finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+    }
+
+    private void togglePrivateSpace(int state, HomeAllApps homeAllApps) {
+        homeAllApps.freeze();
+        try {
+            // Try Toggling Private Space
+            homeAllApps.togglePrivateSpace();
+        }  finally {
+            // UnFreeze
+            homeAllApps.unfreeze();
+        }
+        PrivateProfileManager manager = getFromLauncher(l -> l.getAppsView()
+                .getPrivateProfileManager());
+        waitForLauncherCondition("Private profile toggle to state: " + state + " failed",
+                launcher -> {
+                    manager.reset();
+                    return manager.getCurrentState() == state;
+                },
+                LauncherInstrumentation.WAIT_TIME_MS);
+        // Wait for Launcher UI to be updated with Private Space Items.
+        waitForLauncherUIUpdate();
     }
 
     private void waitForPrivateSpaceSetup() {
@@ -127,7 +244,7 @@
     private void updatePrivateProfileSetupSuccessful(String cli, String output) {
         Log.d(TAG, "updatePrivateProfileSetupSuccessful, cli=" + cli + " " + "output="
                 + output);
-        mPrivateProfileSetupSuccessful = output.startsWith("Success");
+        assertTrue(output, output.startsWith("Success"));
     }
 
     private void updateProfileRemovalSuccessful(String cli, String output) {
@@ -135,6 +252,11 @@
         assertTrue(output, output.startsWith("Success"));
     }
 
+    private boolean isPrivateProfilePresent(String cli, String output) {
+        Log.d(TAG, "updatePrivateProfilePresent, cli=" + cli + " " + "output=" + output);
+        return output.contains(PRIVATE_PROFILE_NAME);
+    }
+
     private String executeShellCommand(String command) {
         try {
             return mDevice.executeShellCommand(command);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index e4caa26..1886ce6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -35,7 +35,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        // b/143488140
         mLauncher.goHome();
         // Start an activity where the gestures start.
         startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
index 7c2d41d..43ebb17 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
@@ -149,6 +149,13 @@
         runTest(TestSurface.WIDGETS, TestCase.LAUNCH_OVERVIEW);
     }
 
+    @Test
+    public void testLaunchSingleRecentTask() {
+        mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
+        startAppFast(CALCULATOR_APP_PACKAGE);
+        mLauncher.goHome().showQuickSwitchView().launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
+    }
+
     private void runTest(@NonNull TestSurface testSurface, @NonNull TestCase testCase) {
         for (int i = 0; i < testCase.mNumAdditionalRunningTasks; i++) {
             startTestActivity(3 + i);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index a9ff161..df73e09 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -15,8 +15,6 @@
  */
 package com.android.quickstep;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
 
 import android.graphics.Rect;
@@ -25,7 +23,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
@@ -48,7 +45,6 @@
 
     @Test
     @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     public void testThreeButtonsTaskbarBoundsAfterConfigChangeDuringIme() {
         Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
         // Go home and to an IME activity (any configuration change would do, as long as it
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 2a54057..bfd7bdb 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -130,7 +130,7 @@
                             .tapMenu()
                             .hasMenuItem("Save app pair"));
         } else {
-            overview.getOverviewActions().assertHasAction("Save app pair");
+            overview.getOverviewGroupActions().assertHasAction("Save app pair");
         }
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index f0683f9..ec245ee 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep;
 
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
 import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.PERSISTENT;
 import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT;
@@ -53,7 +55,7 @@
 
     @Override
     public void setUp() throws Exception {
-        mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+        mTaskbarWasInTransientMode = isTaskbarInTransientMode(getTargetContext());
         setTaskbarMode(mLauncher, isTaskbarTestModeTransient());
         super.setUp();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 374722e..e4f8b6c 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -16,6 +16,8 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
 
 import static org.junit.Assert.assertNotNull;
@@ -30,6 +32,8 @@
 import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
 import com.android.launcher3.tapl.Workspace;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule;
+import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.After;
@@ -84,6 +88,8 @@
     @Test
     @PortraitLandscape
     @NavigationModeSwitch
+    @ScreenRecordRule.ScreenRecord // b/336606166
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/336606166
     public void switchToOverview() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index d04e389..4b20d60 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -17,8 +17,6 @@
 
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
 
 import static org.junit.Assume.assumeTrue;
@@ -26,9 +24,6 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
 import org.junit.Test;
@@ -72,9 +67,6 @@
 
     @Test
     @TaskbarModeSwitch(mode = TRANSIENT)
-    @PortraitLandscape
-    @ScreenRecord // b/317798731
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/321083190
     public void testSwipeToStashAndUnstash() {
         getTaskbar().swipeDownToStash();
         mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index 8eec903..512557b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -17,9 +17,11 @@
 package com.android.quickstep;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -34,7 +36,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.views.TaskView;
@@ -74,6 +75,7 @@
 
     @Test
     public void notShowBorderOnBorderDisabled() {
+        presetBorderStatus(/* enabled= */ true);
         mTaskView.setBorderEnabled(/* enabled= */ false);
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
         mTaskView.onHoverEvent(MotionEvent.obtain(event));
@@ -86,7 +88,7 @@
     }
 
     @Test
-    public void showBorderOnBorderEnabled() {
+    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));
@@ -98,7 +100,18 @@
     }
 
     @Test
+    public void showBorderOnBorderEnabled() {
+        presetBorderStatus(/* enabled= */ false);
+        mTaskView.setBorderEnabled(/* enabled= */ true);
+        verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+                true);
+        verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+                true);
+    }
+
+    @Test
     public void hideBorderOnBorderDisabled() {
+        presetBorderStatus(/* enabled= */ true);
         mTaskView.setBorderEnabled(/* enabled= */ false);
         verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ false, /* animated= */
                 true);
@@ -107,13 +120,35 @@
     }
 
     @Test
+    public void notTriggerAnimatorWhenEnableStatusUnchanged() {
+        presetBorderStatus(/* enabled= */ false);
+        // Border is disabled by default, no animator is triggered after it is disabled again
+        mTaskView.setBorderEnabled(/* enabled= */ false);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
+        verify(mFocusAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
+    }
+
+    private void presetBorderStatus(boolean enabled) {
+        // Make the task view focused and hovered
+        MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+        mTaskView.onHoverEvent(MotionEvent.obtain(event));
+        mTaskView.requestFocus();
+        mTaskView.setBorderEnabled(/* enabled= */ enabled);
+        // Reset invocation count after presetting status
+        reset(mHoverAnimator);
+        reset(mFocusAnimator);
+    }
+
+    @Test
     public void notShowBorderByDefault() {
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
         mTaskView.onHoverEvent(MotionEvent.obtain(event));
-        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
-                true);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
         mTaskView.onFocusChanged(true, 0, new Rect());
-        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
-                true);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
index e5657fb..84ceb33 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
@@ -130,11 +130,10 @@
             boolean condition, Description description) {
         launcher.checkForAnomaly(true, true);
         if (!condition) {
-            final AssertionError assertionError = new AssertionError(message);
             if (description != null) {
-                FailureWatcher.onError(launcher, description, assertionError);
+                FailureWatcher.onError(launcher, description);
             }
-            throw assertionError;
+            throw new AssertionError(message);
         }
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
index dbe4624..4d10f0f 100644
--- a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -22,6 +22,7 @@
 import androidx.test.filters.SmallTest
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
@@ -53,7 +54,13 @@
 class TaskbarPinningControllerTest : TaskbarBaseTestCase() {
     private val taskbarDragLayer = mock<TaskbarDragLayer>()
     private val taskbarSharedState = mock<TaskbarSharedState>()
-    private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false }
+    private var isInDesktopMode = false
+    private val isInDesktopModeProvider = { isInDesktopMode }
+    private val launcherPrefs =
+        mock<LauncherPrefs> {
+            on { get(TASKBAR_PINNING) } doReturn false
+            on { get(TASKBAR_PINNING_IN_DESKTOP_MODE) } doReturn false
+        }
     private val statsLogger = mock<StatsLogManager.StatsLogger>()
     private val statsLogManager = mock<StatsLogManager> { on { logger() } doReturn statsLogger }
     private lateinit var pinningController: TaskbarPinningController
@@ -64,7 +71,8 @@
         whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
         whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
         whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
-        pinningController = spy(TaskbarPinningController(taskbarActivityContext))
+        pinningController =
+            spy(TaskbarPinningController(taskbarActivityContext, isInDesktopModeProvider))
         pinningController.init(taskbarControllers, taskbarSharedState)
     }
 
@@ -95,7 +103,7 @@
     }
 
     @Test
-    fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToPinnedTaskbar() {
+    fun testOnCloseCallback_whenLauncherPreferenceChanged_shouldAnimateToPinnedTaskbar() {
         whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
         doNothing().whenever(pinningController).animateTaskbarPinning(any())
 
@@ -106,7 +114,7 @@
     }
 
     @Test
-    fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToTransientTaskbar() {
+    fun testOnCloseCallback_whenLauncherPreferenceChanged_shouldAnimateToTransientTaskbar() {
         whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
         doNothing().whenever(pinningController).animateTaskbarPinning(any())
 
@@ -199,4 +207,13 @@
         assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
         verify(launcherPrefs, times(1)).put(TASKBAR_PINNING, true)
     }
+
+    @Test
+    fun testRecreateTaskbarAndUpdatePinningValue_whenAnimationEnds_shouldUpdateTaskbarPinningDesktopModePref() {
+        isInDesktopMode = true
+        pinningController.recreateTaskbarAndUpdatePinningValue()
+        verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(false)
+        assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
+        verify(launcherPrefs, times(1)).put(TASKBAR_PINNING_IN_DESKTOP_MODE, true)
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index adaf7ff..ece67af 100644
--- a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -43,6 +43,7 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.never
 import org.mockito.kotlin.spy
@@ -100,8 +101,7 @@
         // Stub methods on appPairsController so that they return mocks
         spyAppPairsController = spy(appPairsController)
         whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
-        whenever(spyAppPairsController.getTopTaskTracker(mockTaskbarActivityContext))
-            .thenReturn(mockTopTaskTracker)
+        doReturn(mockTopTaskTracker).whenever(spyAppPairsController).topTaskTracker
         whenever(mockTopTaskTracker.getCachedTopTask(any())).thenReturn(mockCachedTaskInfo)
         whenever(mockTask1.getKey()).thenReturn(mockTaskKey1)
         whenever(mockTask2.getKey()).thenReturn(mockTaskKey2)
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 68c9bf9..f29df61 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -17,6 +17,8 @@
 
 package com.android.quickstep.util
 
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
 import android.graphics.Bitmap
 import android.graphics.drawable.Drawable
 import android.view.ContextThemeWrapper
@@ -31,16 +33,18 @@
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.views.GroupedTaskView
 import com.android.quickstep.views.IconView
-import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskThumbnailViewDeprecated
 import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
 import com.android.systemui.shared.recents.model.Task
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
@@ -55,7 +59,7 @@
     private val mockSplitSelectStateController: SplitSelectStateController = mock()
     // TaskView
     private val mockTaskView: TaskView = mock()
-    private val mockThumbnailView: TaskThumbnailView = mock()
+    private val mockThumbnailView: TaskThumbnailViewDeprecated = mock()
     private val mockBitmap: Bitmap = mock()
     private val mockIconView: IconView = mock()
     private val mockTaskViewDrawable: Drawable = mock()
@@ -63,7 +67,7 @@
     private val mockGroupedTaskView: GroupedTaskView = mock()
     private val mockTask: Task = mock()
     private val mockTaskKey: Task.TaskKey = mock()
-    private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
+    private val mockTaskContainer: TaskContainer = mock()
     // AppPairIcon
     private val mockAppPairIcon: AppPairIcon = mock()
     private val mockContextThemeWrapper: ContextThemeWrapper = mock()
@@ -79,14 +83,15 @@
     private val transitionInfo: TransitionInfo = mock()
     private val transaction: Transaction = mock()
 
-    lateinit var splitAnimationController: SplitAnimationController
+    private lateinit var splitAnimationController: SplitAnimationController
 
     @Before
     fun setup() {
-        whenever(mockTaskView.thumbnail).thenReturn(mockThumbnailView)
+        whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
         whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
-        whenever(mockTaskView.iconView).thenReturn(mockIconView)
+        whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
         whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
+        whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
 
         whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
         whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
@@ -173,14 +178,13 @@
         // Remove icon view from GroupedTaskView
         whenever(mockIconView.drawable).thenReturn(null)
 
-        whenever(mockTaskIdAttributeContainer.task).thenReturn(mockTask)
-        whenever(mockTaskIdAttributeContainer.iconView).thenReturn(mockIconView)
-        whenever(mockTaskIdAttributeContainer.thumbnailView).thenReturn(mockThumbnailView)
+        whenever(mockTaskContainer.task).thenReturn(mockTask)
+        whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
+        whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
         whenever(mockTask.getKey()).thenReturn(mockTaskKey)
         whenever(mockTaskKey.getId()).thenReturn(taskId)
         whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
-        whenever(mockGroupedTaskView.taskIdAttributeContainers)
-            .thenReturn(Array(1) { mockTaskIdAttributeContainer })
+        whenever(mockGroupedTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
         val splitAnimInitProps: SplitAnimationController.Companion.SplitAnimInitProps =
             splitAnimationController.getFirstAnimInitViews(
                 { mockGroupedTaskView },
@@ -200,7 +204,16 @@
         doNothing()
             .whenever(spySplitAnimationController)
             .composeRecentsSplitLaunchAnimatorLegacy(
-                any(), any(), any(), any(), any(), any(), any(), any(), any())
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any()
+            )
 
         spySplitAnimationController.playSplitLaunchAnimation(
             mockGroupedTaskView,
@@ -219,7 +232,16 @@
 
         verify(spySplitAnimationController)
             .composeRecentsSplitLaunchAnimatorLegacy(
-                any(), any(), any(), any(), any(), any(), any(), any(), any())
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any(),
+                any()
+            )
     }
 
     @Test
@@ -255,6 +277,7 @@
         doNothing()
             .whenever(spySplitAnimationController)
             .composeIconSplitLaunchAnimator(any(), any(), any(), any())
+        doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
 
         spySplitAnimationController.playSplitLaunchAnimation(
             null /* launchingTaskView */,
@@ -276,12 +299,13 @@
     }
 
     @Test
-    fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarContextCorrectly() {
+    fun playsAppropriateSplitLaunchAnimation_playsIconFullscreenLaunchCorrectly() {
         val spySplitAnimationController = spy(splitAnimationController)
-        whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+        whenever(mockAppPairIcon.context).thenReturn(mockContextThemeWrapper)
         doNothing()
             .whenever(spySplitAnimationController)
-            .composeScaleUpLaunchAnimation(any(), any(), any())
+            .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), any())
+        doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
 
         spySplitAnimationController.playSplitLaunchAnimation(
             null /* launchingTaskView */,
@@ -298,7 +322,62 @@
             {} /* finishCallback */
         )
 
-        verify(spySplitAnimationController).composeScaleUpLaunchAnimation(any(), any(), any())
+        verify(spySplitAnimationController)
+            .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), eq(0))
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarCMultiWindow() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+        doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+        spySplitAnimationController.playSplitLaunchAnimation(
+            null /* launchingTaskView */,
+            mockAppPairIcon,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_MULTI_WINDOW))
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarFullscreen() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+        doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+        spySplitAnimationController.playSplitLaunchAnimation(
+            null /* launchingTaskView */,
+            mockAppPairIcon,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_FULLSCREEN))
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.java b/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.java
new file mode 100644
index 0000000..4030b01
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import com.android.quickstep.AbstractQuickStepTest;
+
+import org.junit.Test;
+
+public class TaplTestsPredictionRow extends AbstractQuickStepTest {
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mLauncher.getWorkspace().switchToAllApps();
+    }
+
+    @Test
+    public void testPredictionRow() {
+        mLauncher.getAllApps().getPredictionRowView();
+    }
+}
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
index 45723b0..a16d35a 100644
--- a/res/drawable/ic_install_to_private.xml
+++ b/res/drawable/ic_install_to_private.xml
@@ -22,10 +22,16 @@
     android:viewportHeight="24"
     android:tint="?attr/materialColorOnSurface">
 
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19,5V19H5V5H19ZM19,3H5C3.9,3 3,3.9 3,5V19C3,20.1 3.9,21 5,21H19C20.1,21 21,20.1 21,19V5C21,3.9 20.1,3 19,3Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12.93,12.27L13.5,15.5H10.5L11.07,12.27C10.43,11.94 10,11.27 10,10.5C10,9.4 10.9,8.5 12,8.5C13.1,8.5 14,9.4 14,10.5C14,11.27 13.57,11.94 12.93,12.27Z" />
+    <group>
+        <clip-path
+            android:pathData="M0,0h24v24h-24z"/>
+        <path
+            android:pathData="M12.001,1.999L4.001,4.999V11.089C4.001,16.139 7.411,20.849 12.001,21.999C16.591,20.849 20.001,16.139 20.001,11.089V4.999L12.001,1.999ZM18.001,11.089C18.001,15.089 15.451,18.789 12.001,19.919C8.551,18.789 6.001,15.099 6.001,11.089V6.389L12.001,4.139L18.001,6.389V11.089Z"
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"/>
+        <path
+            android:pathData="M8.501,9.5C8.501,11.08 9.561,12.41 11.001,12.84V18H13.001V17H15.001V15H13.001V12.84C14.441,12.41 15.501,11.09 15.501,9.5C15.501,7.57 13.931,6 12.001,6C10.071,6 8.501,7.57 8.501,9.5ZM13.501,9.5C13.501,10.33 12.831,11 12.001,11C11.171,11 10.501,10.33 10.501,9.5C10.501,8.67 11.171,8 12.001,8C12.831,8 13.501,8.67 13.501,9.5Z"
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"/>
+    </group>
 </vector>
diff --git a/res/drawable/ic_plus.xml b/res/drawable/ic_plus.xml
index 3ab926a..d004f42 100644
--- a/res/drawable/ic_plus.xml
+++ b/res/drawable/ic_plus.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="19dp"
+    android:width="@dimen/widget_cell_add_button_drawable_width"
     android:height="18dp"
     android:viewportWidth="19"
     android:viewportHeight="18">
diff --git a/res/drawable/ic_private_profile_app_scroller_badge.xml b/res/drawable/ic_private_profile_app_scroller_badge.xml
new file mode 100644
index 0000000..ede42b9
--- /dev/null
+++ b/res/drawable/ic_private_profile_app_scroller_badge.xml
@@ -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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+    android:viewportWidth="32"
+    android:viewportHeight="32"
+    android:width="32dp"
+    android:height="32dp">
+    <path
+        android:pathData="M16.0007 2.66602L5.33398 6.66602V14.786C5.33398 21.5194 9.88065 27.7993 16.0007 29.3327C22.1207 27.7993 26.6673 21.5194 26.6673 14.786V6.66602L16.0007 2.66602ZM20.0007 19.9993V22.666H17.334V23.9993H14.6673V17.1193C12.7473 16.546 11.334 14.786 11.334 12.666C11.334 10.0927 13.4273 7.99935 16.0007 7.99935C18.574 7.99935 20.6673 10.0927 20.6673 12.666C20.6673 14.7727 19.254 16.546 17.334 17.1193V19.9993H20.0007Z"
+        android:fillType="evenOdd"
+        android:fillColor="?android:attr/textColorPrimaryInverse" />
+    <path
+        android:pathData="M16 14.666C17.1046 14.666 18 13.7706 18 12.666C18 11.5614 17.1046 10.666 16 10.666C14.8954 10.666 14 11.5614 14 12.666C14 13.7706 14.8954 14.666 16 14.666Z"
+        android:fillColor="?android:attr/textColorPrimaryInverse" />
+</vector>
diff --git a/res/drawable/ic_private_space_with_background.xml b/res/drawable/ic_private_space_with_background.xml
index da199f0..cb37c9a 100644
--- a/res/drawable/ic_private_space_with_background.xml
+++ b/res/drawable/ic_private_space_with_background.xml
@@ -22,9 +22,11 @@
         android:pathData="M48 24A24 24 0 0 1 0 24A24 24 0 0 1 48 24Z"
         android:fillColor="?androidprv:attr/materialColorSurfaceContainerLowest" />
     <path
-        android:pathData="M33.3333 14.6667V33.3333H14.6667V14.6667H33.3333ZM33.3333 12H14.6667C13.2 12 12 13.2 12 14.6667V33.3333C12 34.8 13.2 36 14.6667 36H33.3333C34.8 36 36 34.8 36 33.3333V14.6667C36 13.2 34.8 12 33.3333 12Z"
+        android:pathData="M24.0021 10.6641L13.3354 14.6641V22.7841C13.3354 29.5174 17.8821 35.7974 24.0021 37.3307C30.1221 35.7974 34.6688 29.5174 34.6688 22.7841V14.6641L24.0021 10.6641ZM32.0021 22.7841C32.0021 28.1174 28.6021 33.0507 24.0021 34.5574C19.4021 33.0507 16.0021 28.1307 16.0021 22.7841V16.5174L24.0021 13.5174L32.0021 16.5174V22.7841Z"
+        android:fillType="evenOdd"
         android:fillColor="?attr/materialColorOnSurface" />
     <path
-        android:pathData="M25.2397 24.3597L25.9997 28.6663H21.9997L22.7597 24.3597C21.9063 23.9197 21.333 23.0263 21.333 21.9997C21.333 20.533 22.533 19.333 23.9997 19.333C25.4663 19.333 26.6663 20.533 26.6663 21.9997C26.6663 23.0263 26.093 23.9197 25.2397 24.3597Z"
+        android:pathData="M19.3354 20.6657C19.3354 22.7724 20.7488 24.5457 22.6688 25.119V31.999H25.3354V30.6657H28.0021V27.999H25.3354V25.119C27.2554 24.5457 28.6688 22.7857 28.6688 20.6657C28.6688 18.0924 26.5754 15.999 24.0021 15.999C21.4288 15.999 19.3354 18.0924 19.3354 20.6657ZM26.0021 20.6657C26.0021 21.7724 25.1088 22.6657 24.0021 22.6657C22.8954 22.6657 22.0021 21.7724 22.0021 20.6657C22.0021 19.559 22.8954 18.6657 24.0021 18.6657C25.1088 18.6657 26.0021 19.559 26.0021 20.6657Z"
+        android:fillType="evenOdd"
         android:fillColor="?attr/materialColorOnSurface" />
 </vector>
diff --git a/res/drawable/widget_picker_preview_pane_scroll_thumb.xml b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
new file mode 100644
index 0000000..24f90b0
--- /dev/null
+++ b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
@@ -0,0 +1,31 @@
+<?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.
+  -->
+<!--
+A variation of material's scrollbar_handle_material.xml that has paddings to make it smaller.
+ScrollView's "insideInsets" / "insideOverlay" styles don't consider corner radius applied to scroll
+views, so we apply matching padding to the thumb to align it.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:bottom="@dimen/widget_list_top_bottom_corner_radius"
+        android:top="@dimen/widget_list_top_bottom_corner_radius">
+        <shape
+            android:shape="rectangle"
+            android:tint="?android:attr/colorControlNormal">
+            <solid android:color="#84ffffff" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index 478b887..6be33e8 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -19,9 +19,6 @@
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
             <solid android:color="@color/work_fab_bg_color" />
-            <padding
-                android:left="@dimen/work_profile_footer_padding"
-                android:right="@dimen/work_profile_footer_padding" />
         </shape>
     </item>
 </ripple>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 185207b..cefe394 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -24,7 +24,10 @@
         android:background="@drawable/bg_ps_header"
         android:clipToOutline="true"
         android:gravity="center_vertical"
-        android:orientation="horizontal">
+        android:textDirection="locale"
+        android:orientation="horizontal"
+        android:contentDescription="@string/ps_container_lock_button_content_description"
+        android:importantForAccessibility="yes">
 
     <LinearLayout
         android:id="@+id/settingsAndLockGroup"
@@ -39,7 +42,6 @@
             android:layout_width="@dimen/ps_header_image_height"
             android:layout_height="@dimen/ps_header_image_height"
             android:background="@drawable/ps_settings_background"
-            android:layout_marginEnd="@dimen/ps_header_settings_icon_margin_end"
             android:src="@drawable/ic_ps_settings"
             android:contentDescription="@string/ps_container_settings" />
         <LinearLayout
@@ -48,8 +50,8 @@
             android:layout_height="@dimen/ps_header_image_height"
             android:background="@drawable/ps_lock_background"
             android:gravity="center_vertical"
-            android:layout_marginEnd="@dimen/ps_header_layout_margin"
-            android:contentDescription="@string/ps_container_lock_unlock_button">
+            android:layout_marginEnd="@dimen/ps_lock_button_margin_end"
+            android:contentDescription="@string/ps_container_lock_button_content_description">
             <ImageView
                 android:id="@+id/lock_icon"
                 android:layout_width="@dimen/ps_lock_icon_size"
@@ -95,6 +97,7 @@
         android:gravity="center_vertical"
         android:layout_marginStart="@dimen/ps_header_layout_margin"
         android:text="@string/ps_container_title"
-        android:theme="@style/PrivateSpaceHeaderTextStyle"/>
+        android:theme="@style/PrivateSpaceHeaderTextStyle"
+        android:importantForAccessibility="no"/>
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 12453a5..b6412db 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -46,20 +46,22 @@
             android:layout_gravity="center_vertical"
             android:id="@+id/widget_text_container"
             android:orientation="vertical">
-            <!-- The name of the widget. -->
-            <TextView
-                android:id="@+id/widget_name"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:fadingEdge="horizontal"
-                android:layout_gravity="center_horizontal"
-                android:gravity="center_horizontal|center_vertical"
-                android:singleLine="true"
-                android:maxLines="1"
-                android:textColor="?android:attr/textColorPrimary"
-                android:drawablePadding="@dimen/widget_cell_app_icon_padding"
-                android:textSize="@dimen/widget_cell_font_size" />
+                <!-- The name of the widget. -->
+                <TextView
+                    android:id="@+id/widget_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:fadingEdge="horizontal"
+                    android:layout_gravity="center_horizontal"
+                    android:gravity="center_horizontal|center_vertical"
+                    android:singleLine="true"
+                    android:maxLines="1"
+                    android:textColor="?attr/widgetCellTitleColor"
+                    android:textSize="@dimen/widget_cell_title_font_size"
+                    android:textFontWeight="@integer/widget_cell_title_font_weight"
+                    android:lineHeight="@dimen/widget_cell_title_line_height"
+                    android:drawablePadding="@dimen/widget_cell_app_icon_padding" />
 
                 <!-- The original dimensions of the widget -->
                 <TextView
@@ -67,21 +69,23 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:gravity="center_horizontal"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:textSize="@dimen/widget_cell_font_size"
-                    android:alpha="0.7" />
+                    android:textColor="?attr/widgetCellSubtitleColor"
+                    android:textSize="@dimen/widget_cell_dims_font_size"
+                    android:textFontWeight="@integer/widget_cell_dims_font_weight"
+                    android:lineHeight="@dimen/widget_cell_dims_line_height" />
 
                 <TextView
                     android:id="@+id/widget_description"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:gravity="center_horizontal"
-                    android:textSize="@dimen/widget_cell_font_size"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:maxLines="2"
+                    android:textColor="?attr/widgetCellSubtitleColor"
+                    android:textSize="@dimen/widget_cell_description_font_size"
+                    android:textFontWeight="@integer/widget_cell_description_font_weight"
+                    android:lineHeight="@dimen/widget_cell_description_line_height"
+                    android:maxLines="3"
                     android:ellipsize="end"
-                    android:fadingEdge="horizontal"
-                    android:alpha="0.7" />
+                    android:fadingEdge="horizontal" />
         </LinearLayout>
 
         <Button
@@ -94,12 +98,16 @@
             android:paddingEnd="@dimen/widget_cell_add_button_end_padding"
             android:text="@string/widget_add_button_label"
             android:textColor="?attr/widgetPickerAddButtonTextColor"
-            android:textSize="@dimen/widget_cell_font_size"
+            android:textSize="@dimen/widget_cell_add_button_font_size"
+            android:fontWeight="@integer/widget_cell_add_button_font_weight"
+            android:lineHeight="@dimen/widget_cell_add_button_line_height"
             android:gravity="center"
             android:visibility="gone"
             android:drawableStart="@drawable/ic_plus"
-            android:drawablePadding="8dp"
+            android:drawablePadding="@dimen/widget_cell_add_button_drawable_padding"
             android:drawableTint="?attr/widgetPickerAddButtonTextColor"
+            android:maxLines="1"
+            style="@style/Button.Rounded.Colored"
             android:background="@drawable/widget_cell_add_button_background" />
     </FrameLayout>
 </merge>
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 065c2ed..0a1407e 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -25,11 +25,10 @@
             android:layout_width="@dimen/bottom_sheet_handle_width"
             android:layout_height="@dimen/bottom_sheet_handle_height"
             android:layout_gravity="center_horizontal"
-            android:layout_marginBottom="@dimen/bottom_sheet_handle_margin"
+            android:layout_marginBottom="@dimen/widgets_bottom_sheet_handle_margin"
             android:visibility="gone"
             android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/>
         <TextView
-            style="@style/TextHeadline"
             android:id="@+id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -41,8 +40,13 @@
             android:id="@+id/widgets_table_scroll_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:fadeScrollbars="false"
-            android:layout_marginTop="16dp">
+            android:layout_marginTop="24dp"
+            android:layout_marginBottom="24dp"
+            android:layout_marginHorizontal="@dimen/widget_bottom_sheet_horizontal_margin"
+            android:background="@drawable/widgets_surface_background"
+            android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+            android:clipToOutline="true"
+            android:clipChildren="true">
             <include layout="@layout/widgets_table_container"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/res/layout/widgets_edu.xml b/res/layout/widgets_edu.xml
deleted file mode 100644
index 280c095..0000000
--- a/res/layout/widgets_edu.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher3.views.WidgetsEduView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="bottom"
-    android:gravity="bottom"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:id="@+id/edu_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="@drawable/bg_rounded_corner_bottom_sheet"
-        android:gravity="center_horizontal"
-        android:orientation="vertical"
-        android:paddingHorizontal="@dimen/bottom_sheet_edu_padding"
-        android:paddingTop="@dimen/bottom_sheet_edu_padding">
-
-        <TextView
-            style="@style/TextHeadline"
-            android:id="@+id/edu_header"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:text="@string/widget_education_header"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="24sp"
-            android:layout_marginBottom="16dp"/>
-
-        <TextView
-            android:id="@+id/edu_content"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:text="@string/widget_education_content"
-            android:textSize="14sp"
-            android:textColor="?android:attr/textColorSecondary"
-            android:layout_marginBottom="24dp"/>
-
-        <Button
-            android:id="@+id/edu_close_button"
-            style="@style/Button.Rounded.Colored"
-            android:layout_width="match_parent"
-            android:layout_height="56dp"
-            android:text="@string/widget_education_close_button"
-            android:textSize="16sp"
-            android:textColor="@color/button_text"
-            android:layout_marginBottom="8dp"/>
-    </LinearLayout>
-</com.android.launcher3.views.WidgetsEduView>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 6d26ce3..98f9dac 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -48,8 +48,10 @@
             android:layout_gravity="start|center_vertical"
             android:ellipsize="end"
             android:maxLines="1"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="16sp"
+            android:textColor="?attr/widgetPickerHeaderAppTitleColor"
+            android:textSize="@dimen/widget_picker_header_app_title_font_size"
+            android:textFontWeight="@integer/widget_picker_header_app_title_font_weight"
+            android:lineHeight="@dimen/widget_picker_header_app_title_line_height"
             tools:text="App name" />
 
         <TextView
@@ -58,8 +60,10 @@
             android:layout_height="wrap_content"
             android:ellipsize="end"
             android:maxLines="1"
-            android:textColor="?android:attr/textColorSecondary"
-            android:alpha="0.7"
+            android:textColor="?attr/widgetPickerHeaderAppSubtitleColor"
+            android:textSize="@dimen/widget_picker_header_app_subtitle_font_size"
+            android:textFontWeight="@integer/widget_picker_header_app_subtitle_font_weight"
+            android:lineHeight="@dimen/widget_picker_header_app_subtitle_line_height"
             tools:text="m widgets, n shortcuts" />
 
     </LinearLayout>
diff --git a/res/layout/widgets_list_row_header_two_pane.xml b/res/layout/widgets_list_row_header_two_pane.xml
index bdb2aed..d4baf0a 100644
--- a/res/layout/widgets_list_row_header_two_pane.xml
+++ b/res/layout/widgets_list_row_header_two_pane.xml
@@ -51,7 +51,9 @@
             android:ellipsize="end"
             android:maxLines="1"
             android:textColor="?attr/widgetPickerHeaderAppTitleColor"
-            android:textSize="16sp"
+            android:textSize="@dimen/widget_picker_header_app_title_font_size"
+            android:textFontWeight="@integer/widget_picker_header_app_title_font_weight"
+            android:lineHeight="@dimen/widget_picker_header_app_title_line_height"
             android:duplicateParentState="true"
             tools:text="App name" />
 
@@ -62,7 +64,9 @@
             android:ellipsize="end"
             android:maxLines="1"
             android:textColor="?attr/widgetPickerHeaderAppSubtitleColor"
-            android:alpha="0.7"
+            android:textSize="@dimen/widget_picker_header_app_subtitle_font_size"
+            android:textFontWeight="@integer/widget_picker_header_app_subtitle_font_weight"
+            android:lineHeight="@dimen/widget_picker_header_app_subtitle_line_height"
             android:duplicateParentState="true"
             tools:text="m widgets, n shortcuts" />
 
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index 6c4810c..bb2b7bd 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -94,42 +94,49 @@
             </FrameLayout>
 
             <FrameLayout
-                android:id="@+id/right_pane_container"
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
-                android:layout_weight="0.67"
-                android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
-                android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
-                android:gravity="end"
-                android:layout_gravity="end"
-                android:orientation="horizontal">
-                <ScrollView
-                    android:id="@+id/right_pane_scroll_view"
+                android:layout_weight="0.67">
+                <FrameLayout
+                    android:id="@+id/right_pane_container"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:fillViewport="true">
-                    <LinearLayout
-                        android:orientation="vertical"
+                    android:layout_marginVertical="@dimen/widget_picker_vertical_margin_right_pane"
+                    android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+                    android:gravity="end"
+                    android:layout_gravity="end"
+                    android:orientation="horizontal">
+                    <ScrollView
+                        android:id="@+id/right_pane_scroll_view"
                         android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_vertical"
-                        android:clipToOutline="true"
-                        android:paddingBottom="36dp"
+                        android:layout_height="match_parent"
                         android:background="@drawable/widgets_surface_background"
-                        android:importantForAccessibility="yes"
-                        android:id="@+id/right_pane">
-                        <!-- Shown when there are recommendations to display -->
+                        android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+                        android:clipToOutline="true"
+                        android:fillViewport="true">
                         <LinearLayout
-                            android:id="@+id/widget_recommendations_container"
-                            android:layout_width="match_parent"
-                            android:layout_height="match_parent"
-                            android:background="@drawable/widgets_surface_background"
                             android:orientation="vertical"
-                            android:visibility="gone">
-                            <include layout="@layout/widget_recommendations" />
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:gravity="center_vertical"
+                            android:clipToOutline="true"
+                            android:paddingBottom="36dp"
+                            android:background="@drawable/widgets_surface_background"
+                            android:importantForAccessibility="yes"
+                            android:id="@+id/right_pane">
+                            <!-- Shown when there are recommendations to display -->
+                            <LinearLayout
+                                android:id="@+id/widget_recommendations_container"
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent"
+                                android:background="@drawable/widgets_surface_background"
+                                android:orientation="vertical"
+                                android:visibility="gone">
+                                <include layout="@layout/widget_recommendations" />
+                            </LinearLayout>
                         </LinearLayout>
-                    </LinearLayout>
-                </ScrollView>
+                    </ScrollView>
+                </FrameLayout>
             </FrameLayout>
         </LinearLayout>
     </com.android.launcher3.views.SpringRelativeLayout>
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 276d73e..b3484c9 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -24,12 +24,15 @@
     android:background="@drawable/work_mode_fab_background"
     android:forceHasOverlappingRendering="false"
     android:contentDescription="@string/work_apps_pause_btn_text"
+    android:paddingStart="@dimen/work_mode_fab_background_start_padding"
+    android:paddingEnd="@dimen/work_mode_fab_background_end_padding"
     android:animateLayoutChanges="true">
     <ImageView
         android:id="@+id/work_icon"
         android:layout_width="@dimen/work_fab_icon_size"
         android:layout_height="@dimen/work_fab_icon_size"
         android:importantForAccessibility="no"
+        android:layout_marginEnd="@dimen/work_fab_icon_end_margin"
         android:src="@drawable/ic_corp_off"
         android:tint="@color/work_fab_icon_color"
         android:scaleType="center"/>
@@ -43,7 +46,7 @@
         android:includeFontPadding="false"
         android:textDirection="locale"
         android:text="@string/work_apps_pause_btn_text"
-        android:layout_marginStart="@dimen/work_fab_text_start_margin"
+        android:layout_marginEnd="@dimen/work_fab_text_end_margin"
         android:ellipsize="end"
         android:maxLines="1"
         style="@style/TextHeadline"/>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 7c6aa83..c363dc5 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Neem notas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Voeg by"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Voeg <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Nuttige inligting binne jou bereik"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Jy kan legstukke by jou tuisskerm voeg om inligting te kry sonder om programme oop te maak"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om legstukinstellings te verander"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Het dit"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Verander legstukinstellings"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Deursoek programme"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Laai tans programme …"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om op te stel of oop te maak"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privaat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privaat, ontsluit."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privaat, gesluit."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Sluit"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privaat Ruimte-oorgang"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installeer apps"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index fe5b51a..bc211ef 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"የማስታወሻ አያያዝ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"አክል"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"ምግብር <xliff:g id="WIDGET_NAME">%1$s</xliff:g>ን አክል"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"በጣቶችዎ ጫፎች ላይ ጠቃሚ መረጃ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"መተግበሪያዎችን ሳይከፍቱ መረጃ ለማግኘት በመነሻ ማያ ገጽዎ ላይ ምግብሮችን ማከል ይችላሉ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"የምግብር ቅንብሮችን ለመለወጥ መታ ያድርጉ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ገባኝ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"የምግብር ቅንብሮችን ይለውጡ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"መተግበሪያዎችን ፈልግ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"መተግበሪያዎችን በመጫን ላይ…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ለማዋቀር ወይም ለመክፈት መታ ያድርጉ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"የግል"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"የግል፣ የተከፈተ።"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"የግል፣ የተቆለፈ።"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ቆልፍ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"የግል ቦታ ሽግግር"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"መተግበሪያዎችን ይጫኑ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 6963bb7..becfa8d 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -51,7 +51,7 @@
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"التواصل الاجتماعي"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"الصحة واللياقة البدنية"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"الطقس"</string>
-    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"محتوى مقترَح لك"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"اقتراحاتنا لك"</string>
     <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"تطبيقات \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" المصغّرة على اليسار، والبحث والخيارات على اليمين"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"تدوين الملاحظات"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"إضافة"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"إضافة التطبيق المصغّر \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"معلومات مفيدة في متناول يديك"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"للحصول على معلومات بدون فتح التطبيقات، يمكنك إضافة التطبيقات المصغّرة إلى الشاشة الرئيسية."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"انقر لتغيير إعدادات الأداة"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"حسنًا"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغيير إعدادات الأداة"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"بحث في التطبيقات"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"جارٍ تحميل التطبيقات…"</string>
@@ -175,7 +172,7 @@
     <string name="accessibility_close" msgid="2277148124685870734">"إغلاق"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصية"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string>
-    <string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"ملف العمل"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"تحمل تطبيقات العمل مميّزة بشارة ومرئية لمشرف تكنولوجيا المعلومات."</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"حسنًا"</string>
     <string name="work_apps_paused_title" msgid="3040901117349444598">"تطبيقات العمل متوقفة مؤقتًا"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"النقر للإعداد أو الفتح"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"المساحة الخاصة غير مُقفلة."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"المساحة الخاصة مُقفلة."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"قفل"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"النقل إلى المساحة الخاصة"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"تثبيت التطبيقات"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 7872e45..d2487f8 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"টোকা গ্ৰহণ কৰা"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"যোগ দিয়ক"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট যোগ দিয়ক"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"আপোনাৰ আঙুলিৰে টিপতে উপযোগী তথ্য পাওক"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"এপ্ নোখোলাকৈ তথ্য পাবলৈ আপুনি নিজৰ গৃহ স্ক্ৰীনত ৱিজেট যোগ দিব পাৰে"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ৱিজেটৰ ছেটিং সলনি কৰিবলৈ টিপক"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"বুজি পালোঁ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ৱিজেটৰ ছেটিং সলনি কৰক"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"এপ্‌সমূহ সন্ধান কৰক"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"এপ্‌সমূহ ল’ড কৰি থকা হৈছে…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ছেট আপ কৰিবলৈ টিপক অথবা খোলক"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"প্ৰাইভেট স্পে\'চ লক/আনলক কৰক"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ব্যক্তিগত, আনলক কৰা আছে।"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ব্যক্তিগত, লক কৰা আছে।"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"লক কৰক"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পে’চৰ স্থানান্তৰণ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"এপ্‌ ইনষ্টল কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 0f67a22..145ec69 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Qeydgötürmə"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Əlavə edin"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidcet əlavə edin"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Faydalı məlumatlar barmaqlarınızın ucunda"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Tətbiqləri açmadan məlumat almaq üçün Əsas ekrana vidcet əlavə edə bilərsiniz"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidcet ayarlarını dəyişmək üçün toxunun"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Anladım"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidcet ayarlarını dəyişin"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tətbiqləri axtarın"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Tətbiqlər yüklənir…"</string>
@@ -188,11 +185,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Davam etdirin"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Məxfi sahə"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Toxunaraq ayarlayın və ya açın"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Şəxsi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Şəxsi, kilidli deyil."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Şəxsi, kilidli."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Kilidləyin"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Şəxsi məkana keçid"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Tətbiqlər quraşdırın"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 59c4700..8b69318 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -44,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Neophodne aplikacije"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovno"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novosti i časopisi"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pravljenje beležaka"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajte vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Da biste pronašli informacije bez otvaranja aplikacija, možete da dodate vidžete na početni ekran"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Važi"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promenite podešavanja vidžeta"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste podesili ili otvorili"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prenos privatnog prostora"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index b6e30de..c3b384c 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Дадзенае спалучэнне праграм не падтрымліваецца на гэтай прыладзе"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Каб выкарыстоўваць гэта спалучэнне праграм, раскладзіце прыладу"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Спалучэнне праграм недаступнае"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Націсніце і ўтрымлівайце віджэт для перамяшчэння."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Дакраніцеся двойчы і ўтрымлівайце, каб перамясціць віджэт або выкарыстоўваць спецыяльныя дзеянні."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Стварэнне нататак"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Дадаць"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Дадаць віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Карысная інфармацыя ў вас пад рукой"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Каб не адкрываць праграмы для прагляду патрэбнай інфармацыі, дадайце віджэты на галоўны экран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Націсніце, каб змяніць налады віджэта"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Зразумела"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Змяніць налады віджэта"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук праграм"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Праграмы загружаюцца…"</string>
@@ -125,7 +121,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Дазволіць паварот галоўнага экрана"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Значкі апавяшчэнняў"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укл."</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Уключана"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Выкл."</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -189,11 +185,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Актываваць"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Прыватная вобласць"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Прыватная прастора"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Націсніце, каб наладзіць або адкрыць"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Прыватная"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Прыватная прастора, разблакіравана."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Прыватная прастора, заблакіравана."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Заблакіраваць"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Пераход у прыватную вобласць"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Усталяваць праграмы"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b9b6b60..7915de9 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Тази двойка приложения не се поддържа на устройството"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Отворете устройството, за да използвате тази двойка приложения"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Двойката приложения не е налице"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Докоснете и задръжте за преместване на приспособление"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Докоснете двукратно и задръжте за преместване на приспособление или използвайте персонал. действия."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Водене на бележки"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Добавяне"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавяне на приспособлението „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Лесен достъп до полезна информация"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"За да получавате информация, без да отваряте приложенията, можете да добавите приспособления към началния екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Докоснете, за да промените настройките на приспособлението"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Разбрах"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промяна на настройките на приспособлението"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Търсене в приложенията"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Приложенията се зареждат…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Докоснете за настройване или отваряне"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Частно, отключено."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Частно, заключено."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Заключване"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към личното пространство"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталиране на приложения"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 64b0ba2..a19fbfc 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইসে এই অ্যাপ পেয়ারটি কাজ করে না"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"এই অ্যাপ পেয়ার ব্যবহার করতে ডিভাইস আনফোল্ড করুন"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"অ্যাপ পেয়ার উপলভ্য নেই"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"কোনও উইজেট সরাতে সেটি টাচ করে ধরে রাখুন।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"একটি উইজেট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"নোট নেওয়া"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"যোগ করুন"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট যোগ করুন"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"সহজেই দরকারি তথ্য পান"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"অ্যাপ না খুলেই তথ্য পাওয়ার জন্য, হোম স্ক্রিনে উইজেট যোগ করতে পারবেন"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"উইজেট সেটিংস পরিবর্তন করতে ট্যাপ করুন"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"বুঝেছি"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"উইজেট সেটিংস পরিবর্তন করুন"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"অ্যাপ খুঁজুন"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"অ্যাপ লোড হচ্ছে…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"সরান"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ব্যক্তিগত প্রোফাইলে ইনস্টল করুন"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"প্রাইভেট প্রোফাইলে ইনস্টল করুন"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"সেট-আপ করতে বা খুলতে ট্যাপ করুন"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ব্যক্তিগত, আনলক করা আছে।"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ব্যক্তিগত, লক করা আছে।"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"লক"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পেস ট্রানজিট করা"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"অ্যাপ ইনস্টল করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index d0d4ce6..74fe854 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilješki"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodavanje vidžeta <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Da dobijete informacije bez otvaranja aplikacija, možete dodati vidžete na početni ekran"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da promijenite postavke vidžeta"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Razumijem"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promjena postavki vidžeta"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
@@ -89,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u priv. pr."</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u Privatno"</string>
     <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>
@@ -188,11 +185,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ponovo pokreni"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da postavite ili otvorite"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključaj"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instaliranje aplikacija"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 5d54f2e..50bb41f 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aquesta parella d\'aplicacions no s\'admet en aquest dispositiu"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desplega el dispositiu per utilitzar aquesta parella d\'aplicacions"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La parella d\'aplicacions no està disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Fes doble toc i mantén premut per moure un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Fes doble toc i mantén premut per moure un widget o per utilitzar accions personalitzades."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -52,7 +51,7 @@
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salut i fitnes"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Temps"</string>
-    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments personalitzats"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments per a tu"</string>
     <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la dreta, cerca i opcions a l\'esquerra"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Presa de notes"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Afegeix"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Afegeix el widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informació útil a l\'abast de la mà"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Per obtenir informació sense obrir les aplicacions, pots afegir widgets a la pantalla d\'inici"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca per canviar la configuració del widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Entesos"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Canvia la configuració del widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"S\'estan carregant les aplicacions…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca per configurar o obrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, desbloquejat."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, bloquejat."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueja"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Canvia a Espai privat"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instal·la apps"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 5d93636..736eaab 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikací není na tomto zařízení podporován"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Pokud chcete použít tento pár aplikací, rozložte zařízení"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Dvojice aplikací není k dispozici"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget přesunete klepnutím a podržením."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nezbytnosti"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nejdůležitější aplikace"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Psaní poznámek"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Přidat"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Přidat widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Užitečné informace na dosah"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Pokud chcete mít informace k dispozici bez otevírání aplikací, můžete si na plochu přidat widgety"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím změníte nastavení widgetu"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Rozumím"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Změnit nastavení widgetu"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hledat v aplikacích"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítání aplikací…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavíte nebo otevřete"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Soukromé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Soukromé, odemčeno."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Soukromé, uzamčeno."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zamknout"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Převádění soukromého prostoru"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalovat aplikace"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 3260fb5..7d4e804 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne appsammenknytning understøttes ikke på enheden"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Fold enheden ud for at bruge denne appsammenknytning"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Appsammenknytning er ikke tilgængelig"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Hold en widget nede for at flytte den."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryk to gange, og hold en widget nede for at flytte den eller bruge tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Tilføj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tilføj <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Nyttige oplysninger lige ved hånden"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Hvis du vil have oplysninger uden at åbne apps, kan du føje widgets til din startskærm"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryk for at ændre widgetindstillinger"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Skift widgetindstillinger"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tryk for at konfigurere eller åbne"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, oplåst."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, låst."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private område"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apps"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 78e20b6..230c578 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Gerät aufklappen, um dieses App-Paar zu verwenden"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-Paar nicht verfügbar"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets berühren und halten"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notizen"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Hinzufügen"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ hinzufügen"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Praktische Informationen – immer zur Hand"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Wenn du Informationen erhalten möchtest, ohne Apps zu öffnen, kannst du deinem Startbildschirm Widgets hinzufügen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tippen, um die Widget-Einstellungen zu ändern"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget-Einstellungen ändern"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps finden"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps werden geladen…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Entfernen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App-Info"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privat installieren"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Vertraul. installieren"</string>
     <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>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Zum Einrichten oder Öffnen tippen"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, entsperrt."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, gesperrt."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Sperren"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Sperrzustand des privaten Bereichs wird gerade geändert"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installieren"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index f2d8a15..03fce60 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Αυτό το ζεύγος εφαρμογών δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Ξεδιπλώστε τη συσκευή για να χρησιμοποιήσετε αυτό το ζεύγος εφαρμογών"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Το ζεύγος εφαρμογών δεν είναι διαθέσιμο"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Πατήστε παρατετ. για μετακίνηση γραφ. στοιχείου."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Πατήστε δύο φορές παρατεταμένα για μετακίνηση γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Δημιουργία σημειώσεων"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Προσθήκη"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Προσθήκη του γραφικού στοιχείου <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Χρήσιμες πληροφορίες στη διάθεσή σας"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Για να λάβετε πληροφορίες χωρίς να ανοίξετε εφαρμογές, μπορείτε να προσθέσετε γραφικά στοιχεία στην αρχική οθόνη."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Πατήστε για αλλαγή των ρυθμίσεων του γραφικού στοιχείου"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Το κατάλαβα"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Αλλαγή ρυθμίσεων γραφικού στοιχείου"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Αναζήτηση εφαρμογών"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Φόρτωση εφαρμογών…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Πληροφ. εφαρμογής"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Εγκατ. στο απόρρητο"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται η εφαρμογή"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Πάτημα για ρύθμιση ή άνοιγμα"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Ιδιωτικό"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Ιδιωτικό, ξεκλειδωμένο."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Ιδιωτικό, κλειδωμένο."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Κλείδωμα"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Μετάβαση στον Ιδιωτικό χώρο"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Εγκατάσταση εφαρμογών"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 7061889..37c74a5 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index ec69ea8..a36e96c 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Got it"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 7061889..37c74a5 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 7061889..37c74a5 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 476ffda..04c2dcf 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎Note-taking‎‏‎‎‏‎"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎Add‎‏‎‎‏‎"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎Add ‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget‎‏‎‎‏‎"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎Useful info at your fingertips‎‏‎‎‏‎"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎To get info without opening apps, you can add widgets to your home screen‎‏‎‎‏‎"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎Tap to change widget settings‎‏‎‎‏‎"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎Got it‎‏‎‎‏‎"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎Change widget settings‎‏‎‎‏‎"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎Search apps‎‏‎‎‏‎"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Loading apps…‎‏‎‎‏‎"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎Tap to set up or open‎‏‎‎‏‎"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎Private‎‏‎‎‏‎"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎Private Space Settings‎‏‎‎‏‎"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎Lock/Unlock Private Space‎‏‎‎‏‎"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎Private, unlocked.‎‏‎‎‏‎"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎Private, locked.‎‏‎‎‏‎"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎Lock‎‏‎‎‏‎"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎Private Space Transitioning‎‏‎‎‏‎"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎Install apps‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 012609e..623b183 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"No se admite esta vinculación de apps en este dispositivo"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abre el dispositivo para usar esta vinculación de apps"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La vinculación de apps no está disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén presionado para mover un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Presiona dos veces y mantén presionado para mover un widget o usar acciones personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -49,7 +48,7 @@
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
-    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y bienestar"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Agregar"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Agregar widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Información útil a tu alcance"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Para recibir información de apps sin abrirlas, puedes agregar widgets a la pantalla principal"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Presiona para cambiar la configuración del widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar la configuración del widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando apps…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instala en privado"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
     <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>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Presiona para configurar o abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado (desbloqueado)"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado (bloqueado)"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueo"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pasar a Espacio privado"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instala apps"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 0b0cb41..4df953a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -29,12 +29,11 @@
     <string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Guardar aplicaciones emparejadas"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Guardar apps emparejadas"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"El dispositivo no admite esta aplicación emparejada"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Despliega el dispositivo para usar esta aplicación emparejada"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La aplicación emparejada no está disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -49,7 +48,7 @@
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
-    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y actividad física"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"El tiempo"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Añadir"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Añadir widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Información útil al alcance de la mano"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Para ver información sin abrir una aplicación, puedes añadir widgets a la pantalla de inicio"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar los ajustes del widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar ajustes del widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicaciones"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicaciones…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configurarlo o abrirlo"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Cambiar a espacio privado"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Descarg. apps"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 212b672..226ccd1 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"See rakendusepaar ei ole selles seadmes toetatud"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Selle rakendusepaari kasutamiseks voltige seade lahti"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Rakendusepaar ei ole saadaval"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidina teisaldamiseks puudutage ja hoidke all."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidina teisaldamiseks või kohandatud toimingute kasutamiseks topeltpuudutage ja hoidke all."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lisa avakuvale"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati avakuvale"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Soovitused"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Alustalad"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Põhiasjad"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uudised ja ajakirjad"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Teie lõõgastumiskoht"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Meelelahutus"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Märkmete tegemine"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Lisa"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisa vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Kasulik teave on teie käeulatuses"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Teabe saamiseks rakendusi avamata võite oma avakuvale lisada vidinaid"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Puudutage vidina seadete muutmiseks"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Selge"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidina seadete muutmine"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Otsige rakendusi"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Rakenduste laadimine …"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Seadistamiseks või avamiseks puudutage"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privaatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privaatne, võrgulukuta."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privaatne, lukustatud."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lukk"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privaatse ruumi üleviimine"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Rakenduste installimine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 8ffbea6..b564f57 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -26,15 +26,14 @@
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Deskargatutako aplikazioa modu seguruan desgaitu da"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgetak desgaitu egin dira modu seguruan"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"Lasterbideak ez daude erabilgarri"</string>
-    <string name="home_screen" msgid="5629429142036709174">"Hasierako pantaila"</string>
+    <string name="home_screen" msgid="5629429142036709174">"Orri nagusia"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantaila zatitzea"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Gorde aplikazio parea"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aplikazio pare hori ez da onartzen gailu honetan"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Zabaldu gailua aplikazio pare hau erabiltzeko"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Aplikazio parea ez dago erabilgarri"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Eduki sakatuta widget bat mugitzeko."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Sakatu birritan eta eduki sakatuta widget bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Gehitu"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Gehitu <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informazio erabilgarria beti eskura"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Aplikaziorik ireki beharrik gabe informazioa zuzenean jasotzeko, gehitu widgetak orri nagusian"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Sakatu hau widgeten ezarpenak aldatzeko"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Ados"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Aldatu widgeten ezarpenak"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Bilatu aplikazioetan"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikazioak kargatzen…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Sakatu konfiguratzeko edo irekitzeko"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Pribatua"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribatua, desblokeatuta."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribatua, blokeatuta."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Blokeatu"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Eremu pribaturako trantsizioa"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalatu aplikazioak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 848ebee..2ef33d8 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -44,14 +44,14 @@
     <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="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"منطقه آرامش شما"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"سرگرمی"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"سلامتی و تناسب اندام"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"آب‌وهوا"</string>
-    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهادشده برای شما"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
     <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارک‌های <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینه‌ها در سمت راست"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‏# ابزارک}one{‏# ابزارک}other{‏# ابزارک}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‏# میان‌بر}one{‏# میان‌بر}other{‏# میان‌بر}}"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشت‌برداری"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"دسترسی آسان به اطلاعات سودمند"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"با افزودن ابزارک‌ها به صفحه اصلی می‌توانید اطلاعات را بدون باز کردن برنامه‌ها دریافت کنید"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، ضربه بزنید"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"متوجه‌ام"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزارک"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامه‌ها"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"درحال بارگیری برنامه‌‌ها…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"برای راه‌اندازی یا باز کردن، ضربه بزنید"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"خصوصی، باز."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"خصوصی، قفل."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"قفل کردن"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"انتقال «فضای خصوصی»"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"نصب برنامه‌ها"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index e55c32f..f6d6ab8 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Sovellusparia ei tueta tällä laitteella"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Avaa taitettu laite, niin voit käyttää sovellusparia"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Sovelluspari ei ole saatavilla"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Kosketa pitkään, niin voit siirtää widgetiä."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Kaksoisnapauta ja paina pitkään, niin voit siirtää widgetiä tai käyttää muokattuja toimintoja."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -49,7 +48,7 @@
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uutiset ja aikakauslehdet"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ota rennosti"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Viihde"</string>
-    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Some"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosiaalinen"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Terveys ja kuntoilu"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Sää"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sinulle ehdotetut"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Muistiinpanojen tekeminen"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Lisää"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisää widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Hyödyllisiä tietoja käden ulottuvilla"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Jos haluat nähdä tietoja avaamatta sovelluksia, voit lisätä aloitusnäytölle widgetejä"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Napauta, niin voit muuttaa widgetin asetuksia"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Muuta widgetin asetuksia"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hae sovelluksia"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Ladataan sovelluksia…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Ota käyttöön tai avaa napauttamalla"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Yksityinen"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Yksityinen, lukitsematon."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Yksityinen, lukittu."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lukko"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Yksityisen tilan siirtäminen"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Asenna sovelluksia"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 7578aea..c83f57e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applications"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La Paire d\'applications n\'est pas offerte"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de note"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Renseignements utiles à portée de main"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des informations sans ouvrir d\'applications, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Touchez pour modifier les paramètres du widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications en cours…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer dans privé"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</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>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
@@ -190,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toucher pour configurer ou ouvrir"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Touchez pour configurer ou ouvrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, déverrouillé."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, verrouillé."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transition vers l\'Espace privé"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installer des applications"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 435d3d3..4c72f00 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Dépliez l\'appareil pour utiliser cette paire d\'applications"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La paire d\'applications n\'est pas disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Appuyez de manière prolongée sur un widget pour le déplacer."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Appuyez deux fois et maintenez la pression pour déplacer widget ou utiliser actions personnalisées."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Les bases"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Indispensables"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de notes"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez un widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Infos utiles à portée de main"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des infos sans ouvrir d\'applis, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Appuyez pour modifier les paramètres du widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</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>
     <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>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Appuyer pour ouvrir ou configurer"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, déverrouillé"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, verrouillé"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transition vers Espace privé"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installer applis"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 180a786..3137d94 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"O dispositivo non admite este emparellamento de aplicacións"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desprega o dispositivo para usar este emparellamento de aplicacións"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Non está dispoñible o emparellamento de aplicacións"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén premido un widget para movelo."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dúas veces un widget e manteno premido para movelo ou utiliza accións personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Engadir"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Engadir o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Información útil ao teu alcance"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Se queres obter información sen abrir as aplicacións, podes engadir widgets á pantalla de inicio"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar a configuración do widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar configuración do widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicacións"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicacións…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir aplicación"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
@@ -125,7 +121,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Permitir xirar a pantalla de inicio"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Ao xirar o teléfono"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Puntos de notificacións"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activados"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Opción activada"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivados"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Necesítase acceso ás notificacións"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para que se mostren os puntos de notificacións, activa as notificacións da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configuralo ou abrilo"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transición ao espazo privado"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 931c38a..8ef75fe 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"નોંધ લેવી"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ઉમેરો"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેરો"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ઉપયોગી માહિતી તમારી આંગળીના ટેરવે"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ઍપને ખોલ્યા વિના માહિતી મેળવવા માટે, તમે તમારી હોમ સ્ક્રીનમાં વિજેટ ઉમેરી શકો છો"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"વિજેટના સેટિંગ બદલવા માટે ટૅપ કરો"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"સમજાઈ ગયું"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"વિજેટના સેટિંગ બદલો"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ઍપ શોધો"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"સેટઅપ કરવા કે ખોલવા માટે ટૅપ કરો"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ખાનગી"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ખાનગી સ્પેસ, અનલૉક કરેલી છે."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ખાનગી સ્પેસ, લૉક કરેલી છે."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"લૉક"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ખાનગી સ્પેસ પર સ્થાનાંતરણ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ઍપ ઇન્સ્ટૉલ કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6d83820..5f489ae 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -47,8 +47,8 @@
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ज़रूरी ऐप्लिकेशन"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"खबरों और पत्रिकाओं वाले ऐप्लिकेशन"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"आपके मनोरंजन के लिए"</string>
-    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन वाले ऐप्लिकेशन"</string>
-    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"हेल्थ और फ़िटनेस वाले ऐप्लिकेशन"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"मौसम"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"नोट बनाने से जुड़े विजेट"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"जोड़ें"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोड़ें"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"काम की जानकारी आसानी से पाएं"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ऐप्लिकेशन को खोले बिना उनकी जानकारी पाने के लिए, होम स्क्रीन पर विजेट जोड़े जा सकते हैं"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट की सेटिंग में बदलाव करने के लिए टैप करें"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ठीक है"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेट की सेटिंग में बदलाव करें"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ऐप्लिकेशन खोजें"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ऐप्लिकेशन लोड हो रहे हैं…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"सेट अप करने या खोलने के लिए टैप करें"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"प्राइवेट स्पेस को अनलॉक किया गया."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"प्राइवेट स्पेस को लॉक किया गया."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"प्राइवेट स्पेस की सेटिंग में बदलाव किया जा रहा है"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ऐप्लिकेशन इंस्टॉल करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index e860ea9..db947fe 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilježaka"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Da biste dobili informacije bez otvaranja aplikacija, možete dodati widgete na početni zaslon"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promijenili postavke widgeta"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Shvaćam"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promijenite postavke widgeta"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretraži aplikacije"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Učitavanje aplikacija…"</string>
@@ -89,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliranje u privatni profil"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u privatno"</string>
     <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>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste postavili ili otvorili"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prelazak na privatni prostor"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 69031fe..bdf5aa6 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ezt az alkalmazáspárt nem támogatja az eszköz"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Hajtsa ki az eszközt az alkalmazáspár használatához"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Az alkalmazáspár nem áll rendelkezésre"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tartsa lenyomva a modult az áthelyezéshez."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Modul áthelyezéséhez koppintson duplán, tartsa nyomva az ujját, vagy használjon egyéni műveleteket."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,8 +44,8 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Hozzáadás a kezdőképernyőhöz"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kihagyhatatlanok"</string>
-    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Hírlapok és folyóiratok"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Legfontosabbak"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Újságok és magazinok"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Az Ön relaxáló zónája"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Szórakozás"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Közösségi"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Jegyzetelés"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Hozzáadás"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadása"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Hasznos információk egy koppintásnyira"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Ha az alkalmazások megnyitása nélkül szeretne információhoz jutni, felvehet modulokat a kezdőképernyőre"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ide koppintva módosíthatja a modulbeállításokat"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Értem"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"A modulbeállítások módosítása"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Alkalmazások keresése"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Alkalmazások betöltése…"</string>
@@ -90,9 +86,9 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Törlés"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinfó"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Telepítés privátra"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privát telepítés"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon alkalmazást"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
@@ -191,9 +187,10 @@
     <string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Magánterület"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privát, feloldott."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privát, zárolt."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zárolás"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Átállás privát területre…"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"App telepítése"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 8d78f1c..4a427f4 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Բացեք սարքը՝ այս հավելվածների զույգն օգտագործելու համար"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Հավելվածների զույգը հասանելի չէ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Հպեք և պահեք՝ վիջեթ տեղափոխելու համար։"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Կրկնակի հպեք և պահեք՝ վիջեթ տեղափոխելու համար, կամ օգտվեք հատուկ գործողություններից։"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Նշումների ստեղծում"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Ավելացնել"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ավելացնել <xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթը"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Բոլոր կարևոր տեղեկությունները՝ ձեռքի տակ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Ավելացրեք վիջեթներ ձեր հիմնական էկրանին, որպեսզի տեղեկություններ ստանաք՝ առանց հավելվածները բացելու։"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Հպեք՝ վիջեթի կարգավորումները փոփոխելու համար"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Եղավ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Փոխել վիջեթի կարգավորումները"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Որոնել հավելվածներ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Հավելվածների բեռնում…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Հեռացնել"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ապատեղադրել"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի մասին"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել անձնականում"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել մասնավորում"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Հպեք կարգավորելու կամ բացելու համար"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Մասնավոր"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել մասնավոր տարածքը"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Անձնական, ապակողպված է։"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Անձնական, կողպված է։"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Կողպում"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Անցում մասնավոր տարածք"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Հավելվածների տեղադրում"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 092995c..141a4d2 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -44,14 +44,14 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan ke layar utama"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan ke layar utama"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Saran"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Wajib Coba"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Penting"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Berita &amp; majalah"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona Nyaman Anda"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hiburan"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosial"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kesehatan &amp; kebugaran"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Cuaca"</string>
-    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Saran untuk Anda"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Disarankan untuk Anda"</string>
     <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> di bagian kanan, penelusuran dan opsi di bagian kiri"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pembuatan catatan"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Tambahkan"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Info bermanfaat mudah dilihat"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan info tanpa membuka aplikasi, Anda dapat menambahkan widget ke layar utama"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketuk untuk mengubah setelan widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Oke"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ubah setelan widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Memuat aplikasi…"</string>
@@ -89,9 +86,9 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal secara pribadi"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal di ruang privasi"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan aplikasi"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
@@ -188,11 +185,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Aktifkan lagi"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Ketuk untuk menyiapkan atau membuka"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Pribadi"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Privasi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribadi, tidak terkunci."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribadi, dikunci."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Ruang Pribadi Bertransisi"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instal aplikasi"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 73a7d64..5c4b3e9 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Glósugerð"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Bæta við"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Bæta græjunni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> við"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Gagnlegar upplýsingar innan seilingar"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Þú getur bætt við græjum á heimaskjáinn til að fá upplýsingar án þess að opna forrit"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ýttu til að breyta græjustillingum"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Ég skil"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Breyta græjustillingum"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Leita í forritum"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Hleður forrit…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Ýttu til að setja upp eða opna"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsa leynirými/taka leynirými úr lás"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Lokað, ólæst."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Lokað, læst."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Læsa"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Setja upp forrit"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 8cffb25..bb178f5 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Questa coppia di app non è supportata su questo dispositivo"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Apri il dispositivo per usare questa coppia di app"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La coppia di app non è disponibile"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tocca e tieni premuto per spostare un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tocca due volte e tieni premuto per spostare un widget o per usare le azioni personalizzate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Aggiunta di note"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Aggiungi"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Aggiungi widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informazioni utili a portata di mano"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Per ricevere informazioni senza aprire le app, puoi aggiungere dei widget alla schermata Home"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tocca per modificare le impostazioni del widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifica le impostazioni del widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca nelle app"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Caricamento delle app…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocca per configurare o aprire"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privato"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privato, sbloccato."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privato, bloccato."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Blocca"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transizione dello Spazio privato in corso…"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installa app"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 0d67af5..4140088 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"צריך לפתוח את המכשיר כדי להשתמש בצמד האפליקציות הזה"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"צמד האפליקציות לא זמין"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"הוספת הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"קבלת מידע שימושי בהקשה"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"רוצה לקבל מידע בלי לפתוח אפליקציות? אפשר להוסיף ווידג\'טים למסך הבית"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"אפשר לשנות את הגדרות הווידג\'ט בהקשה"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"הבנתי"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"שינוי הגדרות הווידג\'ט"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"חיפוש אפליקציות"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"טעינת אפליקציות מתבצעת…"</string>
@@ -190,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"אפשר להקיש כדי להגדיר או לפתוח"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"יש להקיש כדי להגדיר או לפתוח"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"פרטי"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"פרטי, פתוח."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"פרטי, נעול."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"נעילה"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"מעבר למרחב הפרטי"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"התקנת אפליקציות"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 50f5ddf..6276a20 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"このデバイスは、このアプリのペア設定に対応していません"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"このアプリのペア設定を使用するには、デバイスを開いてください"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"アプリのペア設定は利用できません"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"長押ししてウィジェットを移動させます。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ウィジェットをダブルタップして長押ししながら移動するか、カスタム操作を使用してください。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"メモ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"追加"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ウィジェットを追加"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ウィジェットで情報を得る"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ホーム画面にウィジェットを追加すると、アプリを開かずに情報を入手できます"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"タップしてウィジェットの設定を変更する"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ウィジェットの設定を変更します"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"アプリを検索"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"アプリを読み込んでいます…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"設定したり開いたりするにはタップしてください"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"プライベート"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"非公開で、ロックが解除されています。"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"非公開で、ロックされています。"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ロック"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"プライベート スペース移行中"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"アプリをインストールする"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index a3c3d87..d6c44ea 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ამ მოწყობილობაზე აღნიშნული აპთა წყვილი არ არის მხარდაჭერილი"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"გაშალეთ მოწყობილობა ამ აპთა წყვილის გამოსაყენებლად"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"აპთა წყვილი მიუწვდომელია"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ორმაგი შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ჩანიშვნა"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"დამატება"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტის დამატება"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ადვილად მისაწვდომი სასარგებლო ინფორმაცია"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"იმისთვის, რომ ინფორმაცია აპების გაუხსნელად მიიღოთ, შეგიძლიათ, მთავარ ეკრანზე ვიჯეტები დაამატოთ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"შეეხეთ ვიჯეტის პარამეტრების შესაცვლელად"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"გასაგებია"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ვიჯეტის პარამეტრების შეცვლა"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"აპების ძიება"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"აპები იტვირთება…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ამოშლა"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"პირადში ინსტალაცია"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"კერძოში ინსტალაცია"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"დასაყენებლად ან გასახსნელად შეეხეთ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"პირადი"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"პირადი (განბლოკილი)."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"პირადი (ჩაკეტილი)."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ჩაკეტვა"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"პირად სივრცეზე გადასვლა"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"აპების ინსტალაცია"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index ff030e8..6fd40e5 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бұл құрылғы қолданбаларды жұптау функциясын қолдамайды."</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Қолданбаларды жұптау функциясын пайдалану үшін құрылғыны ашыңыз."</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Қолданбаларды жұптау функциясы қолжетімді емес."</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетті жылжыту үшін басып тұрыңыз."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетті жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -46,10 +45,10 @@
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті негізгі экранға енгізілді."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ұсыныстар"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Ең қажетті"</string>
-    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Газеттер мен журналдар"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Жаңалықтар мен журналдар"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Жанға жайлы жер"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Ойын-сауық"</string>
-    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Әлеуметтік"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Қоғам"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Денсаулық және фитнес"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ауа райы"</string>
     <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Сізге ұсынылғандар"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ескертпе жазу"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Қосу"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Виджет (<xliff:g id="WIDGET_NAME">%1$s</xliff:g>) қосу"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Қолданбаларды ашпай-ақ ақпарат алу үшін негізгі экранға тиісті виджеттерді қосыңыз."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджет параметрлерін өзгерту үшін түртіңіз."</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Түсінікті"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Виджет параметрлерін өзгерту"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Қолданбаларды іздеу"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Қолданбалар жүктелуде…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Алып тастау"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке профильге орнату"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Құпия профильге орнату"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Реттеу немесе ашу үшін түртіңіз"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Құпия (құлыпталмаған)."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Құпия (құлыптаулы)."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Құлыптау"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Жеке бөлмеге өту"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Қолданбалар орнату"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 243f9f4..7abe7fd 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ការកត់ត្រា"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"បញ្ចូល"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"បញ្ចូលធាតុ​ក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ទទួលបាន​ព័ត៌មានដែលមានប្រយោជន៍​យ៉ាងងាយស្រួល"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ដើម្បីទទួលបាន​ព័ត៌មាន​ដោយមិនចាំបាច់​បើកកម្មវិធី អ្នកអាចបញ្ចូលធាតុ​ក្រាហ្វិកទៅក្នុង​អេក្រង់ដើម​របស់អ្នក"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ចុចដើម្បីប្ដូរការកំណត់ធាតុ​ក្រាហ្វិក"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"យល់ហើយ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ប្ដូរការកំណត់ធាតុ​ក្រាហ្វិក"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ស្វែងរក​កម្មវិធី"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"កំពុងផ្ទុកកម្មវិធី…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ចុចដើម្បីរៀបចំ ឬបើក"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ឯកជន"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ឯកជន បានដោះសោ។"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ឯកជន ជាប់សោ។"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ចាក់សោ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ការផ្លាស់ប្ដូរ Private Space"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ដំឡើង​កម្មវិធី"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 62864cb..01800a8 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯನ್ನು ಬಳಸಲು ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿ"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ಆ್ಯಪ್ ಜೋಡಿ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ವಿಜೆಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ವಿಜೆಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ಟಿಪ್ಪಣಿ ತೆಗೆದುಕೊಳ್ಳುವುದು"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ಸೇರಿಸಿ"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಸೇರಿಸಿ"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ನಿಮ್ಮ ಬೆರಳ ತುದಿಯಲ್ಲಿ ಉಪಯುಕ್ತ ಮಾಹಿತಿ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ಆ್ಯಪ್‌ಗಳನ್ನು ತೆರೆಯದೆಯೇ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು, ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೀವು ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಬಹುದು"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ಅರ್ಥವಾಯಿತು"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ಆ್ಯಪ್‍ಗಳನ್ನು ಹುಡುಕಿ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
@@ -89,7 +85,7 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ಸೆಟಪ್ ಮಾಡಲು ಅಥವಾ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ಖಾಸಗಿ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ಖಾಸಗಿ, ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ಖಾಸಗಿ, ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಪರಿವರ್ತನೆಯಾಗುತ್ತಿದೆ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ಆ್ಯಪ್‌ಗಳನ್ನು ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f97acf1..0b11f1a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"이 앱 페어링은 이 기기에서 지원되지 않습니다"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"이 앱 페어링을 사용하려면 기기를 펼치세요"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"앱 페어링을 사용할 수 없습니다."</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"길게 터치하여 위젯을 이동하세요."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"두 번 탭한 다음 길게 터치하여 위젯을 이동하거나 맞춤 작업을 사용하세요."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"메모"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"추가"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯 추가"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"빠르게 유용한 정보 확인"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"앱을 열지 않고 정보를 확인하려면 홈 화면에 위젯을 추가하세요."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"탭하여 위젯 설정 변경"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"확인"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"위젯 설정 변경"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"앱 검색"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"앱 로드 중…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"삭제"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"앱 정보"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 설치"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 스페이스에 설치"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"탭하여 설정 또는 열기"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"비공개"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"비공개, 잠금 해제됨."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"비공개, 잠김."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"잠금"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"비공개 스페이스 전환"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"앱 설치"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index f908299..6561559 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Эскертме жазуу"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Кошуу"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетин кошуу"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Керектүү маалымат манжаңыздын учунда"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Бир нерсе билүү үчүн колдонмолорду улам ачып убара болбостон, башкы экранга виджеттерди кошуп коюңуз."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджеттин параметрлерин өзгөртүү үчүн таптап коюңуз"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Түшүндүм"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Виджеттин параметрлерин өзгөртүү"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Колдонмолорду издөө"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Колдонмолор жүктөлүүдө…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Тууралоо же ачуу үчүн таптап коюңуз"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Жеке мейкиндиктин параметрлери"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке мейкиндикти кулпулоо/кулпусун ачуу"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Купуя, кулпусу ачык."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Купуя, кулпуланган."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Кулпулоо"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Жеке чөйрөгө өтүү"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Колдонмолорду орнотуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index c215bc8..89be107 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ການຈົດບັນທຶກ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ເພີ່ມ"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ຂໍ້ມູນທີ່ເປັນປະໂຫຍດຢູ່ປາຍນິ້ວຂອງທ່ານ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ເພື່ອຮັບຂໍ້ມູນໂດຍບໍ່ຕ້ອງເປີດແອັບ, ທ່ານສາມາດເພີ່ມວິດເຈັດໃສ່ໂຮມສະກຣີນຂອງທ່ານໄດ້"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ແຕະເພື່ອປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ຊອກຫາແອັບ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ກໍາລັງໂຫຼດແອັບ…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ແຕະເພື່ອຕັ້ງຄ່າ ຫຼື ເປີດ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ສ່ວນຕົວ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ສ່ວນຕົວ, ປົດລັອກແລ້ວ."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ສ່ວນຕົວ, ລັອກແລ້ວ."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ລັອກ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ການປ່ຽນແປງພື້ນທີ່ສ່ວນຕົວ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ຕິດຕັ້ງແອັບ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 1dcb559..9a19094 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ši programų pora šiame įrenginyje nepalaikoma"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Atlenkite įrenginį, kad galėtumėte naudoti šią programų porą."</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Programų pora nepasiekiama"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dukart pal. ir palaik., kad perkeltumėte valdiklį."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dukart palieskite ir palaikykite, kad perkeltumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Užrašų kūrimas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Pridėti"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridėti valdiklį: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Lengvai pasiekiama naudinga informacija"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Jei norite gauti informacijos neatidarę programų, galite pridėti valdiklių pagrindiniame ekrane"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Palieskite, kad pakeistumėte valdiklio nustatymus"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Supratau"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Pakeisti valdiklio nustatymus"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Paieškos programos"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Įkeliamos programos…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Palieskite, kad nustatytumėte arba atidarytumėte"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatus"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatus, atrakintas."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatus, užrakintas."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Užrakinti"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privačios erdvės perkėlimas"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Programų diegimas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e2b1031..2c77a54 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Šis lietotņu pāris netiek atbalstīts šajā ierīcē"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Atveriet ierīci, lai izmantotu šo lietotņu pāri"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Lietotņu pāris nav pieejams"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Lai pārvietotu logrīku, pieskarieties un turiet."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Lai pārvietotu logrīku, uz tā veiciet dubultskārienu un turiet. Varat arī veikt pielāgotas darbības."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Piezīmju pierakstīšana"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Pievienot"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pievienot logrīku <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Ērta piekļuve noderīgai informācijai"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Lai iegūtu informāciju, neatverot lietotnes, varat pievienot sākuma ekrānam logrīkus"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Pieskarieties, lai mainītu logrīka iestatījumus."</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Labi"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mainīt logrīka iestatījumus"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Meklēt lietotnes"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Notiek lietotņu ielāde…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Pieskarieties, lai iestatītu vai atvērtu"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privātā mape"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privāta un nav bloķēta."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privāta un bloķēta."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloķēšana"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pāriet uz privāto mapi"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Lietotņu instalēšana"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 0accd7f..3618e22 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Паров апликации не е поддржан на уредов"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Отворете го уредот за да го користите паров апликации"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Парот апликации не е достапен"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Допрете и задржете за да преместите виџет."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Допрете двапати и задржете за да преместите виџет или користете приспособени дејства."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Фаќање белешки"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додај го виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Корисни информации на дофат на прстите"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"За да добивате информации без да ги отворате апликациите, може да додадете виџети на почетниот екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Допрете за да ги промените поставките за виџетот"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Сфатив"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промени ги поставките за виџетот"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пребарувајте апликации"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Се вчитуваат апликации…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. во приватен"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апликација"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
@@ -131,7 +127,7 @@
     <string name="msg_missing_notification_access" msgid="281113995110910548">"За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Промени ги поставките"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Прикажувај точки за известување"</string>
-    <string name="developer_options_title" msgid="700788437593726194">"Опции за програмери"</string>
+    <string name="developer_options_title" msgid="700788437593726194">"Програмерски опции"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Додавај икони за апликации на почетниот екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови апликации"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
@@ -191,10 +187,11 @@
     <string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Допрете за да поставите или отворите"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Приватен"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Приватен простор"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
-    <string name="ps_container_lock_title" msgid="2640257399982364682">"Брава"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватно, отклучено."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватно, заклучено."</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Заклучи"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Префрлање на „Приватен простор“"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликации"</string>
     <string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталирање апликации во „Приватен простор“"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index e3b6e6b..dde91aa 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ചേർക്കുക"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ചേർക്കുക"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ഉപകാരപ്രദമായ വിവരങ്ങൾ നിങ്ങളുടെ വിരൽത്തുമ്പിൽ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ആപ്പുകൾ തുറക്കാതെ വിവരങ്ങൾ ലഭിക്കാൻ, നിങ്ങൾക്ക് ഹോം സ്ക്രീനിലേക്ക് വിജറ്റുകൾ ചേർക്കാം"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"വിജറ്റ് ക്രമീകരണം മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"മനസ്സിലായി"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"വിജറ്റ് ക്രമീകരണം മാറ്റുക"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ആപ്പുകൾ തിരയുക"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."</string>
@@ -91,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"സ്വകാര്യമായി ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കരുത്"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"സജ്ജീകരിക്കാനോ തുറക്കാനോ ടാപ്പ് ചെയ്യുക"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"സ്വകാര്യം"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്‌പേസ് ക്രമീകരണം"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്‌പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"സ്വകാര്യം, അൺലോക്ക് ചെയ്തിരിക്കുന്നു."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"സ്വകാര്യം, ലോക്ക് ചെയ്തു."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ലോക്ക് ചെയ്യുക"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"പ്രൈവറ്റ് സ്‌പേസ് ട്രാൻസിഷനിംഗ്"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index cc4af0e..ed17387 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Энэ апп хослуулалтыг уг төхөөрөмж дээр дэмждэггүй"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Энэ апп хослуулалтыг ашиглахын тулд төхөөрөмжийг дэлгэнэ үү"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Апп хослуулалт боломжгүй байна"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетийг зөөх бол хүрээд, удаан дарна уу."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетийг зөөх эсвэл захиалгат үйлдлийг ашиглахын тулд хоёр товшоод, удаан дарна уу."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Тэмдэглэл хөтлөх"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Нэмэх"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг нэмэх"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Хэрэгтэй мэдээллээ хурууныхаа үзүүрээр аваарай"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Аппуудыг нээлгүйгээр мэдээлэл авахын тулд та үндсэн нүүрэндээ виджетүүд нэмэх боломжтой"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Жижиг хэрэгслийн тохиргоог өөрчлөхийн тулд товшино уу"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Ойлголоо"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Жижиг хэрэгслийн тохиргоог өөрчлөх"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Апп хайх"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Аппыг ачаалж байна..."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Тохируулах эсвэл нээхийн тулд товших"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Хувийн"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Хувийн, түгжээг тайлсан."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Хувийн, түгжээтэй."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Түгжээ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space-н шилжилт"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Аппуудыг суулгах"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 5eec969..e7287d8 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"या ॲपची जोडीला या डिव्हाइसवर सपोर्ट नाही"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ही ॲपची जोडी वापरण्यासाठी डिव्हाइस अनफोल्ड करा"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ॲपची जोडी उपलब्ध नाही"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"विजेट हलवण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"विजेट हलवण्यासाठी किंवा कस्टम कृती वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"टिपा घेणे"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"जोडा"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोडा"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"तुमच्यासाठी सहज उपलब्ध असलेली माहिती"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ॲप्स न उघडता माहिती मिळवण्यासाठी, तुम्ही तुमच्या होम स्क्रीनवर विजेट जोडू शकता"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट सेटिंग्ज बदलण्यासाठी टॅप करा"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"समजले"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेट सेटिंग्ज बदला"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अ‍ॅप्स शोधा"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"अ‍ॅप्स लोड करत आहे…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"सेट करण्यासाठी किंवा उघडण्यासाठी टॅप करा"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"खाजगी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"खाजगी, अनलॉक केलेली."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"खाजगी, लॉक केलेली."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"खाजगी स्पेस वर स्विच करणे"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"अ‍ॅप्स इंस्टॉल करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 68a9238..099400f 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Maklumat berguna di hujung jari anda"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan maklumat tanpa membuka apl, anda boleh menambahkan widget pada skrin utama anda"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketik untuk menukar tetapan widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Tukar tetapan widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cari apl"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Memuatkan apl…"</string>
@@ -89,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam peribadi"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam persendirian"</string>
     <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>
@@ -190,9 +187,10 @@
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Ketik untuk menyediakan atau membuka"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Peribadi"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Persendirian"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Peribadi, tidak berkunci."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Peribadi, dikunci."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Peralihan Ruang Peribadi"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Pasang apl"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 6a06d0d..01d1a8f 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ဤအက်ပ်တွဲချိတ်ခြင်းကို ဤစက်တွင် ပံ့ပိုးမထားပါ"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ဤအက်ပ်တွဲချိတ်ခြင်းကို သုံးရန် စက်ကိုဖြန့်ပါ"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"အက်ပ်တွဲချိတ်ခြင်းကို မရနိုင်ပါ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ဝိဂျက်ကို ရွှေ့ရန် တို့ပြီး ဖိထားပါ။"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ဝိဂျက်ကို ရွှေ့ရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -46,7 +45,7 @@
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ကို ပင်မစာမျက်နှာတွင် ထည့်လိုက်ပြီ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"အကြံပြုချက်"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"မရှိမဖြစ်များ"</string>
-    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"သတင်းနှင့် မဂ္ဂဇင်း"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"သင်အနားယူသောနေရာ"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ဖျော်ဖြေရေး"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"လူမှုရေး"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"မှတ်စုလိုက်ခြင်း"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ထည့်ရန်"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ထည့်ရန်"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"အသုံးဝင်သော အချက်အလက်များကို အလွယ်တကူ ရယူလိုက်ပါ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"အက်ပ်မဖွင့်ဘဲ အချက်အလက်များရယူရန် ပင်မစာမျက်နှာတွင် ဝိဂျက်များ ထည့်နိုင်သည်"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ဝိဂျက် ဆက်တင်များကို ပြောင်းရန် တို့ပါ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"နားလည်ပြီ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ဝိဂျက် ဆက်တင်များကို ပြောင်းပါ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ရှာဖွေမှု အက်ပ်များ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"အက်ပ်များကို ဖွင့်နေသည်…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"စနစ်ထည့်သွင်းရန် (သို့) ဖွင့်ရန် တို့ပါ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"သီးသန့်"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"သီးသန့် လော့ခ်ဖွင့်ထားသည်။"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"သီးသန့် လော့ခ်ချထားသည်။"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"လော့ခ်ချခြင်း"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"သီးသန့်ချတ်ခန်း အပြောင်းအလဲ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"အက်ပ်ထည့်ခြင်း"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 5a19b9b..56ef9e7 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Åpne enheten for å bruke denne apptilkoblingen"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Apptilkoblingen er ikke tilgjengelig"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Trykk og hold for å flytte en modul."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dobbelttrykk og hold inne for å flytte en modul eller bruke tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Legg til på startskjermen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen er lagt til på startskjermen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Uunnværlige spill"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Anbefalt"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter og tidsskrifter"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Avslappingssonen din"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underholdning"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notatskriving"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Legg til"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Legg til <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Lett tilgjengelig nyttig informasjon"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"For å se informasjon uten å åpne apper kan du legge til moduler på startskjermen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trykk for å endre modulinnstillinger"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Greit"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Endre modulinnstillinger"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søk etter apper"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Laster inn appene …"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Trykk for å konfigurere eller åpne"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat (ulåst)."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat (låst)."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space-overgang"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apper"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 8e06879..4686ba0 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"नोट लेख्ने कार्य"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"हाल्नुहोस्"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हाल्नुहोस्"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"उपयोगी जानकारी सजिलै प्राप्त गर्नुहोस्"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"एपहरू नखोलिकनै जानकारी प्राप्त गर्न तपाईं आफ्नो होम स्क्रिनमा विजेटहरू हाल्न सक्नुहुन्छ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेटका सेटिङ बदल्न ट्याप गर्नुहोस्"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"बुझेँ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेटका सेटिङ बदल्नुहोस्"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"एपहरू खोज्नुहोस्"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"एपहरू लोड गर्दै…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"सेटअप गर्न वा खोल्न ट्याप गर्नुहोस्"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"निजी, अनलक गरिएको।"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"निजी, लक गरिएको।"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"लक गर्नुहोस्"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"निजी स्पेस ट्रान्जिसन गरिँदै छ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"एपहरू इन्स्टल गर्नुहोस्"</string>
diff --git a/res/values-night-v34/colors.xml b/res/values-night-v34/colors.xml
new file mode 100644
index 0000000..af28119
--- /dev/null
+++ b/res/values-night-v34/colors.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+<resources  xmlns:android="http://schemas.android.com/apk/res/android">
+    <color name="widget_picker_secondary_surface_color_dark">
+        @android:color/system_surface_bright_dark</color>
+    <color name="widget_picker_header_app_title_color_dark">
+        @android:color/system_on_surface_dark</color>
+    <color name="widget_picker_header_app_subtitle_color_dark">
+        @android:color/system_on_surface_variant_dark</color>
+    <color name="widget_cell_title_color_dark">
+        @android:color/system_on_surface_dark</color>
+    <color name="widget_cell_subtitle_color_dark">
+        @android:color/system_on_surface_variant_dark</color>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d64e6c3..a61416e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dit app-paar wordt niet ondersteund op dit apparaat"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vouw het apparaat open om dit app-paar te gebruiken"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-paar is niet beschikbaar"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tik en houd vast om een widget te verplaatsen."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en houd vast om een widget te verplaatsen of aangepaste acties te gebruiken."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Aantekeningen maken"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Toevoegen"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toevoegen"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Nuttige informatie binnen handbereik"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Als je informatie wilt krijgen zonder apps te openen, kun je widgets toevoegen aan je startscherm"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om de widgetinstellingen te wijzigen"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widgetinstellingen wijzigen"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps zoeken"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps laden…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om in te stellen of te openen"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, niet vergrendeld."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, vergrendeld."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Vergrendelen"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Overschakelen naar privéruimte"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installeren"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 9cecf07..da70678 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -45,7 +45,7 @@
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ର ୱିଜେଟ ହୋମ ସ୍କ୍ରିନରେ ଯୋଡ଼ାଗଲା"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ପରାମର୍ଶଗୁଡ଼ିକ"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ଅତ୍ୟାବଶ୍ୟକୀୟ"</string>
-    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମେଗାଜିନ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମାଗାଜିନ"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ଆପଣଙ୍କ ଚିଲ ଜୋନ"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ମନୋରଞ୍ଜନ"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ସୋସିଆଲ"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ନୋଟ-ଟେକିଂ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ଯୋଗ କରନ୍ତୁ"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ଉପଯୋଗୀ ସୂଚନା ଆପଣଙ୍କ ପାଖରେ ସହଜରେ ଉପଲବ୍ଧ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ଆପ୍ସକୁ ନଖୋଲି ସୂଚନା ପାଇବା ପାଇଁ, ଆପଣ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନରେ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରିପାରିବେ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ବୁଝିଗଲି"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ଆପ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ଆପ୍‌ ଲୋଡ୍‌ ହେଉଛି..."</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ସେଟ ଅପ କରିବା କିମ୍ବା ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ପ୍ରାଇଭେଟ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ପ୍ରାଇଭେଟ, ଅନଲକ କରାଯାଇଛି।"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ପ୍ରାଇଭେଟ, ଲକ କରାଯାଇଛି।"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ଲକ କରନ୍ତୁ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ପ୍ରାଇଭେଟ ସ୍ପେସ ଟ୍ରାଞ୍ଜିସନିଂ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ଆପ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 17f16f1..3c1a37e 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਦਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਨੂੰ ਵਰਤਣ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਅਣਫੋਲਡ ਕਰੋ"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ਐਪ ਜੋੜਾਬੱਧ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ਕਿਸੇ ਵਿਜੇਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ਵਿਜੇਟ ਲਿਜਾਉਣ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰਕੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਤੁਰੰਤ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ਐਪਾਂ ਨੂੰ ਖੋਲ੍ਹੇ ਬਿਨਾਂ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਤੁਸੀਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ਸਮਝ ਲਿਆ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ਐਪਾਂ ਖੋਜੋ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"ਸੈੱਟਅੱਪ ਕਰਨ ਜਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ਨਿੱਜੀ, ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ਨਿੱਜੀ, ਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ਲਾਕ ਕਰੋ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 18642d7..da6a711 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -44,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Najbardziej przydatne"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notatki"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Użyteczne informacje w zasięgu ręki"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Możesz dodać widżety do ekranu głównego, aby uzyskiwać informacje bez otwierania aplikacji"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Kliknij, aby zmienić ustawienia widżetu"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmień ustawienia widżetu"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Wyszukaj aplikacje"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Ładuję aplikacje…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Kliknij, aby skonfigurować lub otworzyć"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Prywatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Prywatna, bez blokady."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Prywatna, zablokowana."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zablokuj"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Przenoszenie obszaru prywatnego"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instaluj aplikacje"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index fc70150..e07d8cc 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -51,7 +51,7 @@
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociais"</string>
     <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e fitness"</string>
     <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteorologia"</string>
-    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerido para si"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugestões para si"</string>
     <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicione o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis à sua disposição"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Para obter informações sem abrir apps, pode adicionar widgets ao seu ecrã principal"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para alterar as definições do widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Alterar definições do widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"A carregar aplicações…"</string>
@@ -189,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocar para configurar ou abrir"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transição do espaço privado"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 0391efe..3b2aeec 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este Par de apps não está disponível no dispositivo"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abra o dispositivo para usar este Par de apps"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"O Par de apps não está disponível"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque e pressione para mover um widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes e mantenha a tela pressionada para mover um widget ou usar ações personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Anotações"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicionar o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis ao seu alcance"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Para acessar informações sem precisar abrir os apps, adicione widgets à sua tela inicial"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para mudar as configurações do widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Ok"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mudar as configurações do widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Carregando apps…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privada, desbloqueado."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privada, bloqueado."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Espaço particular em transição"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 07f3cf4..d4c303e 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Perechea de aplicații nu este acceptată pe acest dispozitiv"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Deschide dispozitivul ca să folosești această pereche de aplicații"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Perechea de aplicații nu este disponibilă"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Atinge și ține apăsat pentru a muta un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Atinge de două ori și ține apăsat pentru a muta un widget sau folosește acțiuni personalizate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Luare de notițe"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Adaugă"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adaugă widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informații utile la îndemâna ta"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Pentru a primi informații fără să deschizi aplicațiile, poți adăuga widgeturi pe ecranul de pornire"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Atinge ca să schimbi setările pentru widgeturi"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifică setările pentru widgeturi"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Caută aplicații"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Se încarcă aplicații…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Atinge pentru a configura sau a deschide"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, deblocat."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, blocat."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Blochează"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Tranziție pentru spațiul privat"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalează aplicații"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ee1caef..a7e2666 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -44,7 +44,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="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Развлечение и общение"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Создание заметок"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Добавить"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавить виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Вся нужная информация перед глазами"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Чтобы не открывать приложения каждый раз, когда нужна информация, добавьте виджеты на главный экран."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Нажмите, чтобы изменить настройки виджета"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"ОК"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Изменить настройки виджета"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Поиск приложений"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Загрузка приложений…"</string>
@@ -89,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Убрать"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Приватная установка"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Частная установка"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
@@ -188,11 +185,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Возобновить"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фильтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Личное пространство"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Частное пространство"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Нажмите, чтобы настроить или открыть"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Личное, разблокировано."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Личное, заблокировано."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Блокировка"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Переход к личному пространству"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Установить приложения"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 25cc880..fce3499 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"මෙම යෙදුම් යුගලය මෙම උපාංගයෙහි සහාය නොදක්වයි"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"මෙම යෙදුම් යුගලය භාවිතා කිරීමට උපාංගය දිගහරින්න"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"යෙදුම් යුගලයක් නොමැත"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"විජට් එකක් ගෙන යාමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"විජට් එකක් ගෙන යාමට හෝ අභිරුචි ක්‍රියා භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"සටහන් කර ගැනීම"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"එක් කරන්න"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව එක් කරන්න"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"ප්‍රයෝජනවත් තොරතුරු ඔබගේ ඇඟිලි තුඩු අග"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"යෙදුම් විවෘත නොකර තොරතුරු ලබා ගැනීම සඳහා, ඔබට ඔබගේ මුල් තිරයට විජට් එක් කළ හැකිය"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"විජට් සැකසීම් වෙනස් කිරීමට තට්ටු කරන්න"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"තේරුණා"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"විජට් සැකසීම් වෙනස් කරන්න"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"යෙදුම් සොයන්න"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"යෙදුම් පූරණය වෙමින්…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"පිහිටුවීමට හෝ විවෘත කිරීමට තට්ටු කරන්න"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"පෞද්ගලික"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"පුද්ගලි, අගුලු හරින ලදි."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"පුද්ගලික, අගුලු දමන ලදි."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"අගුළු දමන්න"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"පෞද්ගලික අවකාශ සංක්‍රමණය"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"යෙදුම් ස්ථාපනය කරන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index cf87cf8..a93c332 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridať miniaplikáciu <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Užitočné informácie poruke"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Ak chcete získavať informácie bez otvárania aplikácií, môžete si na plochu pridať miniaplikácie"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím zmeňte nastavenia miniaplikácie"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Dobre"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmena nastavení miniaplikácie"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hľadať aplikácie"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítavajú sa aplikácie…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavte alebo otvorte"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Súkromné"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Súkromné, odomknuté."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Súkromné, uzamknuté."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Uzamknúť"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prechod súkromného priestoru"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Inštalovať aplikácie"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 8693ea2..26fed22 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -44,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na začetni zaslon"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>« je dodan na začetni zaslon."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlogi"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nepogrešljivo"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnove"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novice in revije"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaš kotiček za sprostitev"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Razvedrilo"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ustvarjanje zapiskov"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajanje pripomočka »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Koristne informacije na dosegu prstov"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Če si želite podatke ogledati brez odpiranja aplikacij, lahko na začetni zaslon dodate pripomočke."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dotaknite se, če želite spremeniti nastavitve pripomočka."</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Razumem"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Spreminjanje nastavitev pripomočka"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Iskanje programov"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Nalaganje aplikacij …"</string>
@@ -91,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Namesti v zasebno"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj aplikacij"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
@@ -189,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da nastavite ali odprete"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da ga nastavite ali odprete"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Zasebno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Zasebno, odklenjeno."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Zasebno, zaklenjeno."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaklepanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Preklapljanje zasebnega prostora"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Nameščanje aplikacij"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 7643c4a..95c0782 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ky çift aplikacionesh nuk mbështetet në këtë pajisje"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Shpalose pajisjen për të përdorur këtë çift aplikacionesh"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Çifti i aplikacioneve nuk ofrohet"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Prek dhe mbaj shtypur një miniaplikacion për ta zhvendosur."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Trokit dy herë dhe mbaje shtypur një miniapliikacion për ta zhvendosur atë ose për të përdorur veprimet e personalizuara."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Informacione të dobishme në majë të gishtave të tu"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Për të marrë informacione pa i hapur aplikacionet, mund të shtosh miniaplikacione në ekranin bazë"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trokit për të ndryshuar cilësimet e miniaplikacionit"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"E kuptova"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ndrysho cilësimet e miniaplikacionit"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Kërko për aplikacione"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Po ngarkon aplikacionet..."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Trokit për të konfiguruar ose për të hapur"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, e shkyçur."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, e kyçur."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Kyç"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Kalimi te \"Hapësira private\""</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Instalo aplikacionet"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 9535dc0..9eaae37 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -44,7 +44,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="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Прављење бележака"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додајте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Корисне информације надохват руке"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Да бисте пронашли информације без отварања апликација, можете да додате виџете на почетни екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Важи"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промените подешавања виџета"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Претражите апликације"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Апликације се учитавају…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Додирните да бисте подесили или отворили"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Приватно"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватно, откључано."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватно, закључано."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Закључавање"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Пренос приватног простора"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликације"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index fd34dee..5d13f13 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vik upp enheten för att använda de här apparna som ska användas tillsammans"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-paret är inte tillgängligt"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tryck länge för att flytta en widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryck snabbt två gånger och håll kvar för att flytta en widget eller använda anpassade åtgärder."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Favoriter"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Viktigt"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter och tidskrifter"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Koppla av"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underhållning"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Lägg till"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lägg till widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Användbar information nära till hands"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Om du vill ha information utan att öppna appar kan du lägga till widgetar på startskärmen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryck för att ändra inställningarna för widgeten"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ändra inställningarna för widgeten"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sök efter appar"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Läser in appar …"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Tryck för att ställa in eller öppna"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, olåst."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, låst."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Överföring av privat rum"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Installera appar"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8d74b83..830b56d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Kuandika madokezo"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Weka"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Weka wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Maelezo muhimu, popote ulipo"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Ili upate maelezo bila kufungua programu, unaweza kuweka wijeti kwenye skrini yako ya kwanza"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Gusa ili ubadilishe mipangilio ya wijeti"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Nimeelewa"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Badilisha mipangilio ya wijeti"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tafuta programu"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Inapakia programu..."</string>
@@ -189,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"Gusa ili uweke mipangilio au ufungue"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Gusa uweke mipangilio au ufungue"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Faragha"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Ya faragha, imefunguliwa."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Ya faragha, imefungwa."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Funga"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Mabadiliko ya Nafasi ya Faragha"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Sakinisha programu"</string>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index cc1f09e..eda9b2d 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -40,6 +40,7 @@
 <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
     <dimen name="spring_loaded_hotseat_top_margin">65dp</dimen>
+    <dimen name="min_hotseat_icon_space">17dp</dimen>
 
 <!-- Dragging -->
     <dimen name="drop_target_top_margin">64dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 6baa6b1..061cfb3 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"இந்தச் சாதனத்தில் இந்த ஆப்ஸ் ஜோடி ஆதரிக்கப்படவில்லை"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"இந்த ஆப்ஸ் ஜோடியைப் பயன்படுத்த சாதனத்தை விரியுங்கள்"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ஆப்ஸ் ஜோடி கிடைக்கவில்லை"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"விட்ஜெட்டை நகர்த்தத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"விட்ஜெட்டை நகர்த்த இருமுறை தட்டிப் பிடிக்கவும் அல்லது பிரத்தியேகச் செயல்களைப் பயன்படுத்தவும்."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"குறிப்பெடுத்தல்"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"சேர்"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்டைச் சேர்க்கும்"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"விரல்நுனியில் பயனுள்ள தகவல்களைப் பெறுங்கள்"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"முகப்புத் திரையில் விட்ஜெட்டுகளைச் சேர்த்து ஆப்ஸைத் திறக்காமலேயே தகவல்களைப் பெறலாம்"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"விட்ஜெட் அமைப்புகளை மாற்றத் தட்டவும்"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"சரி"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"விட்ஜெட் அமைப்புகளை மாற்றும்"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ஆப்ஸில் தேடுக"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ஆப்ஸை ஏற்றுகிறது…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"அமைக்கவோ திறக்கவோ தட்டுங்கள்"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"தனிப்பட்டது"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"தனிப்பட்டது, அன்லாக் செய்யப்பட்டுள்ளது."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"தனிப்பட்டது, லாக் செய்யப்பட்டுள்ளது."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"பூட்டு"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ஆப்ஸை நிறுவுதல்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index daa90fa..d3aea7b 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -44,7 +44,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">"Essentials"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"నిత్యావసరాలు"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"వార్తలు &amp; మ్యాగజైన్లు"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"మీరు ప్రశాంతంగా ఉండే ప్రదేశం"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"వినోదం"</string>
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"నోట్-టేకింగ్"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"జోడించండి"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్‌ను జోడించండి"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"మీ చేతివేళ్ల మీద ఉపయోగకరమైన సమాచారం"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"యాప్‌లను తెరవకుండా సమాచారాన్ని పొందడానికి, మీరు మీ మొదటి స్క్రీన్‌కు విడ్జెట్‌లను జోడించవచ్చు"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"విడ్జెట్ సెట్టింగ్‌లను మార్చడానికి ట్యాప్ చేయండి"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"అర్థమైంది"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"విడ్జెట్ సెట్టింగ్‌లను మార్చండి"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"యాప్‌ల కోసం సెర్చ్ చేయండి"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్‌లను లోడ్ చేస్తోంది…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"సెటప్ చేయడానికి లేదా తెరవడానికి ట్యాప్ చేయండి"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ప్రైవేట్"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్‌లు"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్‌ను లాక్/అన్‌లాక్ చేయండి"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ప్రైవేట్, అన్‌లాక్ చేయబడింది."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ప్రైవేట్, లాక్ చేయబడింది."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"లాక్ చేయండి"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ప్రైవేట్ స్పేస్ కేటాయించడం జరుగుతుంది"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"యాప్‌లను ఇన్‌స్టాల్ చేయండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index efcd36f..1a7c6d1 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"การจดบันทึก"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"เพิ่ม"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"เข้าถึงข้อมูลที่เป็นประโยชน์ได้จากปลายนิ้ว"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"หากต้องการรับข้อมูลโดยไม่เปิดแอป ให้เพิ่มวิดเจ็ตลงในหน้าจอหลัก"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"แตะเพื่อเปลี่ยนการตั้งค่าวิดเจ็ต"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"รับทราบ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"เปลี่ยนการตั้งค่าวิดเจ็ต"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ค้นหาแอป"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"กำลังโหลดแอป…"</string>
@@ -89,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"นำออก"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ข้อมูลแอป"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในส่วนตัว"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในแบบส่วนตัว"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"แตะเพื่อตั้งค่าหรือเปิด"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ส่วนตัว"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ส่วนตัว ปลดล็อกอยู่"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ส่วนตัว ล็อกอยู่"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"ล็อก"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"การเปลี่ยนไปใช้พื้นที่ส่วนตัว"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ติดตั้งแอป"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 27c2dd8..87b89e3 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pagtatala"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Idagdag"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Idagdag ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Abot-kamay na mahalagang impormasyon"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Para makakuha ng impormasyon nang hindi nagbubukas ng mga app, puwede kang magdagdag ng mga widget sa iyong home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"I-tap para baguhin ang mga setting ng widget"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Baguhin ang mga setting ng widget"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
@@ -91,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pribadong i-install"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi ng app"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"I-tap para i-set up o buksan"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Pribado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribado, naka-unlock."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribado, naka-lock."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"I-lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pag-transition ng Pribadong Space"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Mag-install ng mga app"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b4743d6..5440378 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu uygulama çifti bu cihazda desteklenmiyor"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bu uygulama çiftini kullanmak için katlanmış durumda olan cihazı açın"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Uygulama çifti kullanılamıyor"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget\'ı taşımak için dokunup basılı tutun."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Widget\'ı taşımak veya özel işlemleri kullanmak için iki kez dokunup basılı tutun."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,7 @@
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
-    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaçırmamanız gerekenler"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Önemliler"</string>
     <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Haberler ve dergiler"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Huzur alanınız"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Eğlence"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Not alma"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Ekle"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ekle"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Faydalı bilgiler parmaklarınızın ucunda"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Uygulama açmadan bilgi almak için ana ekranınıza widget ekleyebilirsiniz"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Widget ayarlarını değiştirmek için dokunun"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Anladım"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget ayarlarını değiştir"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Uygulamalarda ara"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Uygulamalar yükleniyor…"</string>
@@ -90,9 +86,9 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Sil"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükleyin"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükle"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulama önerme"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Kurmak veya açmak için dokunun"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Gizli"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Gizli, kilidi açık."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Gizli, kilitli."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Kilit"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Gizli Alana Geçiş"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Uygulamaları yükleme"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index d09e51b..50c8f01 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ці два додатки не можна одночасно використовувати на цьому пристрої"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Розкладіть пристрій, щоб одночасно використовувати ці два додатки"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Одночасне використання двох додатків недоступне"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Натисніть і втримуйте, щоб перемістити віджет."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двічі натисніть і втримуйте віджет, щоб перемістити його або виконати інші дії."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,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="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ваша зона розваг"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Розваги"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Створення нотаток"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Додати"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додати віджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Корисна інформація завжди під рукою"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Щоб отримувати інформацію, не відкриваючи додатки, ви можете додати на головний екран віджети"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Натисніть, щоб змінити налаштування віджета"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Змінити налаштування віджета"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук додатків"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Завантаження додатків…"</string>
@@ -190,10 +186,11 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"Натисніть, щоб налаштувати або відкрити"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Натисніть, щоб налаштувати чи відкрити"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Приватні"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватний простір, розблоковано."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватний простір, заблоковано."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Заблокувати"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Перехід у приватний простір"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Установити додатки"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 50334a0..9cd3e07 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -67,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"نوٹ لکھنا"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"شامل کریں"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ شامل کریں"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"مفید معلومات کو آسانی سے حاصل کریں"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"ایپس کو کھولے بغیر معلومات حاصل کرنے کے لیے آپ اپنی ہوم اسکرین پر ویجیٹس شامل کر سکتے ہیں"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ویجیٹ ترتیبات تبدیل کرنے کے لیے تھپتھپائیں"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"سمجھ آ گئی"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ویجیٹ ترتیبات تبدیل کریں"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ایپس تلاش کریں"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ایپس لوڈ کی جا رہی ہیں…"</string>
@@ -192,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"سیٹ اپ کرنے یا کھولنے کے لیے تھپتھپائیں"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"نجی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"نجی اسپیس غیر مقفل ہے۔"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"نجی اسپیس مقفل ہے۔"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"مقفل کریں"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"نجی اسپیس کی منتقلی"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"ایپس انسٹال کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 795a495..36df592 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu ilova jufti ushbu qurilmada ishlamaydi"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bu ilova juftidan foydalanish uchun qurilmani oching"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Ikkita ilovadan bir vaqtda foydalanish mumkin emas"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidjetni bosib turgan holatda suring."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -46,7 +45,7 @@
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
     <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Asosiy ilovalar"</string>
-    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Gazeta va jurnallar"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Yangiliklar va jurnallar"</string>
     <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sokin hududingiz"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hordiq"</string>
     <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Ijtimoiy"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Qayd olish"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Chiqarish"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjetini chiqarish"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Barcha kerakli axborot doim yoningizda"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Kerakli ilovalarni ochmasdan turib ulardan axborot olish uchun vidjetlarni bosh ekranga chiqaring"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidjet sozlamalarini oʻzgartirish uchun bosing"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidjet sozlamalarini oʻzgartirish"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Ilovalarni qidirish"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Ilovalar yuklanmoqda…"</string>
@@ -191,9 +187,10 @@
     <string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Sozlash yoki ochish uchun bosing"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Yopiq"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Maxfiy"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Shaxsiy, ochildi."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Shaxsiy, qulflandi."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Qulflash"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Maxfiy joyga almashtirish"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Ilovalar oʻrnatish"</string>
diff --git a/res/values-v34/colors.xml b/res/values-v34/colors.xml
new file mode 100644
index 0000000..26d3712
--- /dev/null
+++ b/res/values-v34/colors.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+<resources  xmlns:android="http://schemas.android.com/apk/res/android">
+    <color name="widget_picker_secondary_surface_color_light">
+        @android:color/system_surface_bright_light</color>
+    <color name="widget_picker_header_app_title_color_light">
+        @android:color/system_on_surface_light</color>
+    <color name="widget_picker_header_app_subtitle_color_light">
+        @android:color/system_on_surface_variant_light</color>
+    <color name="widget_cell_title_color_light">
+        @android:color/system_on_surface_light</color>
+    <color name="widget_cell_subtitle_color_light">
+        @android:color/system_on_surface_variant_light</color>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 99bf064..01c7736 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cặp ứng dụng này không hoạt động được trên thiết bị này"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Hãy mở thiết bị để dùng cặp ứng dụng này"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Hiện không có cặp ứng dụng này"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Chạm và giữ để di chuyển một tiện ích."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Nhấn đúp và giữ để di chuyển một tiện ích hoặc sử dụng các thao tác tùy chỉnh."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ghi chú"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Thêm"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Thông tin hữu ích ngay trong tầm tay bạn"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Để nhận thông tin mà không cần mở các ứng dụng, bạn có thể thêm tiện ích vào màn hình chính"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Nhấn để thay đổi chế độ cài đặt tiện ích"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Tôi hiểu"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Thay đổi chế độ cài đặt tiện ích"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tìm kiếm ứng dụng"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Đang tải ứng dụng…"</string>
@@ -92,7 +88,7 @@
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Cài đặt ở chế độ riêng tư"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Không đề xuất ứng dụng"</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>
     <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>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Nhấn để thiết lập hoặc mở"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Riêng tư"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Riêng tư, đã mở khoá."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Riêng tư, đã khoá."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Khoá"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Chuyển đổi sang không gian riêng tư"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Cài đặt ứng dụng"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 2b4abe1..a18aab6 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"在该设备上无法使用此应用对"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"展开设备即可使用此应用组合"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"应用对不可用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住即可移动微件。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -45,7 +44,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="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
     <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娱乐"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"记事"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"添加"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"添加“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"实用信息触手可及"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"要想不打开应用就能获取信息,您可以将相应微件添加到主屏幕"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"点按即可更改微件设置"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"知道了"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"更改微件设置"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜索应用"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"正在加载应用…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"点按即可设置或打开"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私密"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私密,未锁定。"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私密,已锁定。"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"锁定"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"私密空间转换"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"安装应用"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index a48ca7e..e2adcc9 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"此裝置不支援此應用程式配對"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"打開裝置即可使用此應用程式配對"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"應用程式配對無法使用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"輕觸並按住即可移動小工具。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"㩒兩下之後㩒住,就可以郁小工具或者用自訂操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"加<xliff:g id="WIDGET_NAME">%1$s</xliff:g>小工具"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"實用資訊,唾手可得"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增至主畫面,就可以直接查看資料,無需開啟應用程式"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕按即可變更小工具設定"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"知道了"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"變更小工具設定"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"正在載入應用程式…"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"輕按即可設定或開啟"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私人,未鎖定。"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私人,已鎖定。"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"上鎖"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"轉為「私人空間」"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 66e504c..f5eafe4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"這部裝置不支援這組應用程式配對"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"展開裝置即可使用這組應用程式配對"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"這個應用程式配對無法使用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"按住即可移動小工具。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"輕觸兩下並按住即可移動小工具或使用自訂操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"新增「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"實用資訊隨手可得"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增到主畫面,就可以直接查看資訊,不必開啟應用程式"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕觸即可變更小工具設定"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"我知道了"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"變更小工具設定"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"正在載入應用程式…"</string>
@@ -90,7 +86,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資訊"</string>
-    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人空間中"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"輕觸即可設定或開啟"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私人,未鎖定。"</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私人,已鎖定。"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"鎖定"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"轉換私人空間狀態"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 9a90e1e..6de2436 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -33,8 +33,7 @@
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Lokhu kubhanqwa kwe-app akusekelwa kule divayisi"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vula idivayisi ukuze usebenzise lokhu kubhanqwa kwe-app"</string>
-    <!-- no translation found for app_pair_not_available (3556767440808032031) -->
-    <skip />
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Ukubhangqwa kwe-app akutholakali"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Thinta uphinde ubambe ukuze uhambise iwijethi."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Thepha kabili uphinde ubambe ukuze uhambise iwijethi noma usebenzise izindlela ezingokwezifiso."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -68,10 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ukuthatha amanothi"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"Engeza"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"Engeza iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Ulwazi oluwusizo phambi nje kwakho"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Ukuze uthole ulwazi ngaphandle kokuvula ama-app, ungakwazi ukwengeza amawijethi kusikrini sakho sasekhaya"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Thepha ukuze ushintshe amasethingi ewijethi"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Ngiyezwa"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Shintsha amasethingi ewijethi"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sesha izinhlelo zokusebenza"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Ilayisha izinhlelo zokusebenza..."</string>
@@ -193,7 +189,8 @@
     <string name="private_space_secondary_label" msgid="9203933341714508907">"Thepha ukuze usethe noma uvule"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Okuyimfihlo"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
+    <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Iyimfihlo, ivuliwe."</string>
+    <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Iyimfihlo, ikhiyiwe."</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"Khiya"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Ukuguqulwa Kwendawo Yangasese"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"Faka ama-app"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index b3a25c0..be8b2e1 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -76,6 +76,8 @@
     <attr name="widgetPickerCollapseHandleColor" format="color"/>
     <attr name="widgetPickerAddButtonBackgroundColor" format="color"/>
     <attr name="widgetPickerAddButtonTextColor" format="color"/>
+    <attr name="widgetCellTitleColor" format="color" />
+    <attr name="widgetCellSubtitleColor" format="color" />
 
     <!-- BubbleTextView specific attributes. -->
     <declare-styleable name="BubbleTextView">
@@ -204,17 +206,6 @@
          defaults to 2 * numHotseatIcons -->
         <attr name="numExtendedHotseatIcons" format="integer" />
 
-        <!-- alignment of hotseat to the grid.
-        Not applicable for 3 button mode when taskbar is enabled -->
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpan" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelPortrait" format="integer" />
-
         <!-- Spacing to have at the end of the nav buttons in large screen 3 button nav,
              defaults to @dimen/taskbar_button_margin_default -->
         <attr name="inlineNavButtonsEndSpacing" format="reference" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a620eb0..ce80964 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -90,6 +90,8 @@
     <color name="drop_target_hover_button_color_light">#D3E3FD</color>
     <color name="drop_target_hover_button_color_dark">#0842A0</color>
 
+    <color name="taskbar_running_app_indicator_color">#000000</color>
+
     <color name="preload_icon_accent_color_light">#00668B</color>
     <color name="preload_icon_background_color_light">#B5CAD7</color>
     <color name="preload_icon_accent_color_dark">#4BB6E8</color>
@@ -115,6 +117,8 @@
     <color name="widget_picker_collapse_handle_color_light">#C4C7C5</color>
     <color name="widget_picker_add_button_background_color_light">#0B57D0</color>
     <color name="widget_picker_add_button_text_color_light">#0B57D0</color>
+    <color name="widget_cell_title_color_light">@color/material_color_on_surface</color>
+    <color name="widget_cell_subtitle_color_light">@color/material_color_on_surface_variant</color>
 
     <color name="widget_picker_primary_surface_color_dark">#1F2020</color>
     <color name="widget_picker_secondary_surface_color_dark">#393939</color>
@@ -132,6 +136,8 @@
     <color name="widget_picker_collapse_handle_color_dark">#444746</color>
     <color name="widget_picker_add_button_background_color_dark">#062E6F</color>
     <color name="widget_picker_add_button_text_color_dark">#FFFFFF</color>
+    <color name="widget_cell_title_color_dark">@color/material_color_on_surface</color>
+    <color name="widget_cell_subtitle_color_dark">@color/material_color_on_surface_variant</color>
 
     <color name="material_color_on_secondary_fixed_variant">#3F4759</color>
     <color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 393a197..a808a3f 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -76,6 +76,7 @@
     <string name="taskbar_model_callbacks_factory_class" translatable="false"></string>
     <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>
     <!--  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>
@@ -222,4 +223,11 @@
     <string-array name="skip_private_profile_shortcut_packages" translatable="false">
         <item>com.android.settings</item>
     </string-array>
+
+    <!-- Legacy list of components supporting multiple instances.
+         DO NOT ADD TO THIS LIST.  Apps should use the PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI
+         property to declare multi-instance support in V+. This resource should match the resource
+         of the same name in SystemUI. -->
+    <string-array name="config_appsSupportMultiInstancesSplit">
+    </string-array>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a056e81..54edab4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -147,13 +147,15 @@
     <dimen name="work_fab_height">56dp</dimen>
     <dimen name="work_fab_radius">16dp</dimen>
     <dimen name="work_fab_icon_size">24dp</dimen>
-    <dimen name="work_fab_text_start_margin">8dp</dimen>
+    <dimen name="work_fab_icon_end_margin">12dp</dimen>
+    <dimen name="work_fab_text_end_margin">16dp</dimen>
     <dimen name="work_card_padding_horizontal">10dp</dimen>
     <dimen name="work_fab_width">214dp</dimen>
     <dimen name="work_card_button_height">52dp</dimen>
     <dimen name="work_fab_margin">16dp</dimen>
     <dimen name="work_fab_margin_bottom">20dp</dimen>
-    <dimen name="work_mode_fab_padding">16dp</dimen>
+    <dimen name="work_mode_fab_background_start_padding">16dp</dimen>
+    <dimen name="work_mode_fab_background_end_padding">4dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_edu_card_margin">16dp</dimen>
     <dimen name="work_edu_card_radius">16dp</dimen>
@@ -177,18 +179,39 @@
     <!-- Widget tray -->
     <dimen name="widget_cell_vertical_padding">8dp</dimen>
     <dimen name="widget_cell_horizontal_padding">8dp</dimen>
-    <dimen name="widget_cell_font_size">14sp</dimen>
+    <dimen name="widget_cell_title_font_size">14sp</dimen>
+    <integer name="widget_cell_title_font_weight">500</integer>
+    <dimen name="widget_cell_title_line_height">20sp</dimen>
+    <dimen name="widget_cell_dims_font_size">14sp</dimen>
+    <integer name="widget_cell_dims_font_weight">400</integer>
+    <dimen name="widget_cell_dims_line_height">20sp</dimen>
+    <dimen name="widget_cell_description_font_size">12sp</dimen>
+    <integer name="widget_cell_description_font_weight">400</integer>
+    <dimen name="widget_cell_description_line_height">16sp</dimen>
     <dimen name="widget_cell_app_icon_size">24dp</dimen>
     <dimen name="widget_cell_app_icon_padding">8dp</dimen>
     <dimen name="widget_cell_add_button_height">48dp</dimen>
     <dimen name="widget_cell_add_button_start_padding">8dp</dimen>
+    <dimen name="widget_cell_add_icon_button_start_padding">16dp</dimen>
     <dimen name="widget_cell_add_button_end_padding">16dp</dimen>
+    <dimen name="widget_cell_add_button_scroll_padding">24dp</dimen>
+    <dimen name="widget_cell_add_button_font_size">14sp</dimen>
+    <integer name="widget_cell_add_button_font_weight">500</integer>
+    <dimen name="widget_cell_add_button_line_height">20sp</dimen>
+    <dimen name="widget_cell_add_button_drawable_padding">8dp</dimen>
+    <dimen name="widget_cell_add_button_drawable_width">19dp</dimen>
 
     <dimen name="widget_tabs_button_horizontal_padding">4dp</dimen>
     <dimen name="widget_tabs_horizontal_padding">16dp</dimen>
     <dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
     <dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
     <dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
+    <dimen name="widget_picker_header_app_title_font_size">16sp</dimen>
+    <integer name="widget_picker_header_app_title_font_weight">500</integer>
+    <dimen name="widget_picker_header_app_title_line_height">24sp</dimen>
+    <dimen name="widget_picker_header_app_subtitle_font_size">14sp</dimen>
+    <integer name="widget_picker_header_app_subtitle_font_weight">400</integer>
+    <dimen name="widget_picker_header_app_subtitle_line_height">20sp</dimen>
     <dimen name="widget_recommendations_table_vertical_padding">8dp</dimen>
     <!-- Bottom margin for the search and recommended widgets container without work profile -->
     <dimen name="search_and_recommended_widgets_container_bottom_margin">16dp</dimen>
@@ -205,6 +228,9 @@
     <!-- Margin applied to the recycler view with search bar & the list of widget apps below it. -->
     <dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
     <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
+    <dimen name="widget_picker_vertical_margin_right_pane">24dp</dimen>
+    <!-- Margin on sides of the widgets scrollview in widgets bottom sheet -->
+    <dimen name="widget_bottom_sheet_horizontal_margin">16dp</dimen>
 
     <dimen name="widget_preview_shadow_blur">0.5dp</dimen>
     <dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -388,6 +414,9 @@
     <dimen name="min_hotseat_icon_space">18dp</dimen>
     <dimen name="max_hotseat_icon_space">50dp</dimen>
     <dimen name="min_hotseat_qsb_width">0dp</dimen>
+    <dimen name="taskbar_running_app_indicator_height">0dp</dimen>
+    <dimen name="taskbar_running_app_indicator_width">0dp</dimen>
+    <dimen name="taskbar_running_app_indicator_top_margin">0dp</dimen>
 
     <!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
     <dimen name="transient_taskbar_padding">0dp</dimen>
@@ -472,6 +501,7 @@
     <dimen name="bottom_sheet_handle_width">32dp</dimen>
     <dimen name="bottom_sheet_handle_height">4dp</dimen>
     <dimen name="bottom_sheet_handle_margin">16dp</dimen>
+    <dimen name="widgets_bottom_sheet_handle_margin">24dp</dimen>
     <dimen name="bottom_sheet_handle_corner_radius">2dp</dimen>
 
     <!-- State transition -->
@@ -486,13 +516,13 @@
     <dimen name="default_ime_height">300dp</dimen>
 
     <!-- Private Space parameters -->
-    <dimen name="ps_container_corner_radius">24dp</dimen>
-    <dimen name="ps_header_height">64dp</dimen>
+    <dimen name="ps_container_corner_radius">28dp</dimen>
+    <dimen name="ps_header_height">72dp</dimen>
     <dimen name="ps_header_relative_layout_height">48dp</dimen>
     <dimen name="ps_header_image_height">48dp</dimen>
     <dimen name="ps_header_text_height">24dp</dimen>
     <dimen name="ps_header_layout_margin">16dp</dimen>
-    <dimen name="ps_header_settings_icon_margin_end">4dp</dimen>
+    <dimen name="ps_lock_button_margin_end">12dp</dimen>
     <dimen name="ps_header_text_size">16sp</dimen>
     <dimen name="ps_button_height">40dp</dimen>
     <dimen name="ps_button_width">40dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e1c7d64..c3d4273 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -139,20 +139,10 @@
          placeholder text is the widget name. [CHAR_LIMIT=none] -->
     <string name="widget_add_button_content_description">Add <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
 
-    <!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
-         [CHAR_LIMIT=NONE] -->
-    <string name="widget_education_header">Useful info at your fingertips</string>
-    <!-- Dialog text. This dialog lets a user know how they can use widgets on their phone.
-         [CHAR_LIMIT=NONE] -->
-    <string name="widget_education_content">To get info without opening apps, you can add widgets to your home screen</string>
-
     <!-- Text on an educational tip on widget informing users that they can change widget settings.
          [CHAR_LIMIT=NONE] -->
     <string name="reconfigurable_widget_education_tip">Tap to change widget settings</string>
 
-    <!-- Text on the button that closes the education dialog about widgets. [CHAR_LIMIT=50] -->
-    <string name="widget_education_close_button">Got it</string>
-
     <!-- Spoken text for screen readers. This text is for an icon that lets the user change a
          widget's settings. [CHAR_LIMIT=50] -->
     <string name="widget_reconfigure_button_content_description">Change widget settings</string>
@@ -487,13 +477,15 @@
     <string name="ps_container_title">Private</string>
     <!-- Description for Private Space Settings button -->
     <string name="ps_container_settings">Private Space Settings</string>
-    <!-- Description for Private Space Lock/Unlock button -->
-    <string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
+    <!-- Description for Private Space Unlock button -->
+    <string name="ps_container_unlock_button_content_description">Private, unlocked.</string>
+    <!-- Description for Private Space Lock button -->
+    <string name="ps_container_lock_button_content_description">Private, locked.</string>
     <string name="ps_container_lock_title">Lock</string>
     <!-- Description for Private Space Transition button -->
     <string name="ps_container_transition">Private Space Transitioning</string>
     <!-- Title for Private Space install app icon -->
-    <string name="ps_add_button_label">Install apps</string>
+    <string name="ps_add_button_label">Install</string>
     <!-- Content description for install app icon -->
     <string name="ps_add_button_content_description">Install apps to Private Space</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 00b962e..6d99084 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -268,6 +268,10 @@
             @color/widget_picker_add_button_background_color_light</item>
         <item name="widgetPickerAddButtonTextColor">
             @color/widget_picker_add_button_text_color_light</item>
+        <item name="widgetCellTitleColor">
+            @color/widget_cell_title_color_light</item>
+        <item name="widgetCellSubtitleColor">
+            @color/widget_cell_subtitle_color_light</item>
     </style>
     <style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
@@ -303,6 +307,10 @@
             @color/widget_picker_add_button_background_color_dark</item>
         <item name="widgetPickerAddButtonTextColor">
             @color/widget_picker_add_button_text_color_dark</item>
+        <item name="widgetCellTitleColor">
+            @color/widget_cell_title_color_dark</item>
+        <item name="widgetCellSubtitleColor">
+            @color/widget_cell_subtitle_color_dark</item>
     </style>
 
     <style name="FastScrollerPopup" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index c9a44a1..1d0dbff 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -168,7 +168,6 @@
         launcher:numFolderRows="3"
         launcher:numFolderColumns="3"
         launcher:numHotseatIcons="6"
-        launcher:hotseatColumnSpanLandscape="4"
         launcher:numAllAppsColumns="6"
         launcher:isScalable="true"
         launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_6_5"
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 4ccf3db..876b643 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -70,7 +70,6 @@
             TYPE_ICON_SURFACE,
             TYPE_OPTIONS_POPUP_DIALOG,
             TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP,
-            TYPE_WIDGETS_EDUCATION_DIALOG,
             TYPE_TASKBAR_EDUCATION_DIALOG,
             TYPE_TASKBAR_ALL_APPS,
             TYPE_ADD_TO_HOME_CONFIRMATION,
@@ -98,7 +97,6 @@
     public static final int TYPE_OPTIONS_POPUP_DIALOG = 1 << 14;
 
     public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 15;
-    public static final int TYPE_WIDGETS_EDUCATION_DIALOG = 1 << 16;
     public static final int TYPE_TASKBAR_EDUCATION_DIALOG = 1 << 17;
     public static final int TYPE_TASKBAR_ALL_APPS = 1 << 18;
     public static final int TYPE_ADD_TO_HOME_CONFIRMATION = 1 << 19;
@@ -111,16 +109,16 @@
             | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
             | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
             | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
-            | TYPE_WIDGETS_EDUCATION_DIALOG | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS
-            | TYPE_OPTIONS_POPUP_DIALOG | TYPE_ADD_TO_HOME_CONFIRMATION
-            | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_TASKBAR_PINNING_POPUP | TYPE_PIN_IME_POPUP;
+            | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG
+            | TYPE_ADD_TO_HOME_CONFIRMATION | TYPE_TASKBAR_OVERLAY_PROXY
+            | TYPE_TASKBAR_PINNING_POPUP | TYPE_PIN_IME_POPUP;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
-            | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG
-            | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG
-            | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_PIN_IME_POPUP;
+            | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_TASKBAR_EDUCATION_DIALOG
+            | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG | TYPE_TASKBAR_OVERLAY_PROXY
+            | TYPE_PIN_IME_POPUP;
 
     /** Type of popups that should get exclusive accessibility focus. */
     public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index b46d7e2..b51e850 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -136,6 +136,7 @@
     private final Rect mWidgetViewNewRect = new Rect();
     private final @Nullable LauncherAppWidgetHostView.CellChildViewPreLayoutListener
             mCellChildViewPreLayoutListener;
+    private final @NonNull OnLayoutChangeListener mWidgetViewLayoutListener;
 
     private int mXDown, mYDown;
 
@@ -177,6 +178,9 @@
         mDragAcrossTwoPanelOpacityMargin = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.resize_frame_invalid_drag_across_two_panel_opacity_margin);
         mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
+
+        mWidgetViewLayoutListener =
+                (v, l, t, r, b, oldL, oldT, oldR, oldB) -> setCornerRadiusFromWidget();
     }
 
     @Override
@@ -211,15 +215,6 @@
         DragLayer dl = launcher.getDragLayer();
         AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
                 .inflate(R.layout.app_widget_resize_frame, dl, false);
-        if (widget.hasEnforcedCornerRadius()) {
-            float enforcedCornerRadius = widget.getEnforcedCornerRadius();
-            ImageView imageView = frame.findViewById(R.id.widget_resize_frame);
-            Drawable d = imageView.getDrawable();
-            if (d instanceof GradientDrawable) {
-                GradientDrawable gd = (GradientDrawable) d.mutate();
-                gd.setCornerRadius(enforcedCornerRadius);
-            }
-        }
         frame.setupForWidget(widget, cellLayout, dl);
         ((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
 
@@ -228,6 +223,18 @@
         frame.post(() -> frame.snapToWidget(false));
     }
 
+    private void setCornerRadiusFromWidget() {
+        if (mWidgetView != null && mWidgetView.hasEnforcedCornerRadius()) {
+            float enforcedCornerRadius = mWidgetView.getEnforcedCornerRadius();
+            ImageView imageView = findViewById(R.id.widget_resize_frame);
+            Drawable d = imageView.getDrawable();
+            if (d instanceof GradientDrawable) {
+                GradientDrawable gd = (GradientDrawable) d.mutate();
+                gd.setCornerRadius(enforcedCornerRadius);
+            }
+        }
+    }
+
     private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
             DragLayer dragLayer) {
         mCellLayout = cellLayout;
@@ -317,6 +324,9 @@
                 .log(LAUNCHER_WIDGET_RESIZE_STARTED);
 
         setOnKeyListener(this);
+
+        setCornerRadiusFromWidget();
+        mWidgetView.addOnLayoutChangeListener(mWidgetViewLayoutListener);
     }
 
     public boolean beginResizeIfPointInRegion(int x, int y) {
@@ -729,6 +739,7 @@
             mWidgetView.setLayoutTransition(null);
         }
         mDragLayer.removeView(this);
+        mWidgetView.removeOnLayoutChangeListener(mWidgetViewLayoutListener);
     }
 
     private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 1049314..633091d 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -412,6 +412,8 @@
     public static <T extends BaseActivity> T fromContext(Context context) {
         if (context instanceof BaseActivity) {
             return (T) context;
+        } else if (context instanceof ActivityContextDelegate) {
+            return (T) ((ActivityContextDelegate) context).mDelegate;
         } else if (context instanceof ContextWrapper) {
             return fromContext(((ContextWrapper) context).getBaseContext());
         } else {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 83236d1..2a8298f 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -46,6 +46,7 @@
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
 import android.util.Property;
+import android.util.Size;
 import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -182,6 +183,13 @@
     private Animator mDotScaleAnim;
     private boolean mForceHideDot;
 
+    // These fields, related to showing running apps, are only used for Taskbar.
+    private final Size mRunningAppIndicatorSize;
+    private final int mRunningAppIndicatorTopMargin;
+    private final Paint mRunningAppIndicatorPaint;
+    private final Rect mRunningAppIconBounds = new Rect();
+    private boolean mIsRunning;
+
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mStayPressed;
     @ViewDebug.ExportedProperty(category = "launcher")
@@ -248,6 +256,16 @@
                 defaultIconSize);
         a.recycle();
 
+        mRunningAppIndicatorSize = new Size(
+                getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_width),
+                getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_height));
+        mRunningAppIndicatorTopMargin =
+                getResources().getDimensionPixelSize(
+                        R.dimen.taskbar_running_app_indicator_top_margin);
+        mRunningAppIndicatorPaint = new Paint();
+        mRunningAppIndicatorPaint.setColor(getResources().getColor(
+                R.color.taskbar_running_app_indicator_color, context.getTheme()));
+
         mLongPressHelper = new CheckLongPressHelper(this);
 
         mDotParams = new DotRenderer.DrawParams();
@@ -394,6 +412,12 @@
         setDownloadStateContentDescription(info, info.getProgressLevel());
     }
 
+    /** Updates whether the app this view represents is currently running. */
+    @UiThread
+    public void updateRunningState(boolean isRunning) {
+        mIsRunning = isRunning;
+    }
+
     protected void setItemInfo(ItemInfoWithIcon itemInfo) {
         setTag(itemInfo);
     }
@@ -620,6 +644,7 @@
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
         drawDotIfNecessary(canvas);
+        drawRunningAppIndicatorIfNecessary(canvas);
     }
 
     /**
@@ -631,7 +656,7 @@
         if (!mForceHideDot && (hasDot() || mDotParams.scale > 0)) {
             getIconBounds(mDotParams.iconBounds);
             Utilities.scaleRectAboutCenter(mDotParams.iconBounds,
-                    IconShape.getNormalizationScale());
+                    IconShape.INSTANCE.get(getContext()).getNormalizationScale());
             final int scrollX = getScrollX();
             final int scrollY = getScrollY();
             canvas.translate(scrollX, scrollY);
@@ -640,6 +665,22 @@
         }
     }
 
+    /** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
+    protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
+        if (!mIsRunning || mDisplay != DISPLAY_TASKBAR) {
+            return;
+        }
+        getIconBounds(mRunningAppIconBounds);
+        // TODO(b/333872717): update color, shape, and size of indicator
+        int indicatorTop = mRunningAppIconBounds.bottom + mRunningAppIndicatorTopMargin;
+        canvas.drawRect(
+                mRunningAppIconBounds.centerX() - mRunningAppIndicatorSize.getWidth() / 2,
+                indicatorTop,
+                mRunningAppIconBounds.centerX() + mRunningAppIndicatorSize.getWidth() / 2,
+                indicatorTop + mRunningAppIndicatorSize.getHeight(),
+                mRunningAppIndicatorPaint);
+    }
+
     @Override
     public void setForceHideDot(boolean forceHideDot) {
         if (mForceHideDot == forceHideDot) {
@@ -1230,4 +1271,13 @@
     public boolean canShowLongPressPopup() {
         return getTag() instanceof ItemInfo && ShortcutUtil.supportsShortcuts((ItemInfo) getTag());
     }
+
+    /** Returns the package name of the app this icon represents. */
+    public String getTargetPackageName() {
+        Object tag = getTag();
+        if (tag instanceof ItemInfo itemInfo) {
+            return itemInfo.getTargetPackage();
+        }
+        return null;
+    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 72758f2..7e9e864 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -33,7 +33,6 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -115,7 +114,6 @@
     @Thunk final int[] mTempLocation = new int[2];
 
     @Thunk final Rect mTempOnDrawCellToRect = new Rect();
-    final PointF mTmpPointF = new PointF();
 
     protected GridOccupancy mOccupied;
     public GridOccupancy mTmpOccupied;
@@ -123,7 +121,7 @@
     private OnTouchListener mInterceptTouchListener;
 
     private final ArrayList<DelegatedCellDrawing> mDelegatedCellDrawings = new ArrayList<>();
-    final PreviewBackground mFolderLeaveBehind = new PreviewBackground();
+    final PreviewBackground mFolderLeaveBehind = new PreviewBackground(getContext());
 
     private static final int[] BACKGROUND_STATE_ACTIVE = new int[] { android.R.attr.state_active };
     private static final int[] BACKGROUND_STATE_DEFAULT = EMPTY_STATE_SET;
@@ -197,16 +195,11 @@
     public static final int REORDER_ANIMATION_DURATION = 150;
     @Thunk final float mReorderPreviewAnimationMagnitude;
 
-    private final ArrayList<View> mIntersectingViews = new ArrayList<>();
-    private final Rect mOccupiedRect = new Rect();
     public final int[] mDirectionVector = new int[2];
 
     ItemConfiguration mPreviousSolution = null;
-    private static final int INVALID_DIRECTION = -100;
 
     private final Rect mTempRect = new Rect();
-    private final RectF mTempRectF = new RectF();
-    private final float[] mTmpFloatArray = new float[4];
 
     private static final Paint sPaint = new Paint();
 
@@ -1163,9 +1156,6 @@
             mDragCellSpan[0] = spanX;
             mDragCellSpan[1] = spanY;
 
-            // Apply color extraction on a widget when dragging.
-            applyColorExtractionOnWidget(dragObject, mDragCell, spanX, spanY);
-
             final int oldIndex = mDragOutlineCurrent;
             mDragOutlineAnims[oldIndex].animateOut();
             mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
@@ -1186,19 +1176,6 @@
         }
     }
 
-    /** Applies the local color extraction to a dragging widget object. */
-    private void applyColorExtractionOnWidget(DropTarget.DragObject dragObject, int[] targetCell,
-            int spanX, int spanY) {
-        // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
-        View view = dragObject.dragView.getContentView();
-        if (view instanceof LauncherAppWidgetHostView) {
-            int screenId = mCellLayoutContainer.getCellLayoutId(this);
-            cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
-
-            ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, this, screenId);
-        }
-    }
-
     @SuppressLint("StringFormatMatches")
     public String getItemMoveDescription(int cellX, int cellY) {
         if (mContainerType == HOTSEAT) {
diff --git a/src/com/android/launcher3/DevicePaddings.java b/src/com/android/launcher3/DevicePaddings.java
index 08fb47b..8494d11 100644
--- a/src/com/android/launcher3/DevicePaddings.java
+++ b/src/com/android/launcher3/DevicePaddings.java
@@ -47,7 +47,7 @@
     private static final String WORKSPACE_BOTTOM_PADDING = "workspaceBottomPadding";
     private static final String HOTSEAT_BOTTOM_PADDING = "hotseatBottomPadding";
 
-    private static final String TAG = DevicePaddings.class.getSimpleName();
+    private static final String TAG = "DevicePaddings";
     private static final boolean DEBUG = false;
 
     ArrayList<DevicePadding> mDevicePaddings = new ArrayList<>();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 6cb33a8..a667c96 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -47,6 +47,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.ResourcesCompat;
 
 import com.android.launcher3.CellLayout.ContainerType;
@@ -212,6 +213,8 @@
     // Hotseat
     public int numShownHotseatIcons;
     public int hotseatCellHeightPx;
+    private int mHotseatColumnSpan;
+    private int mHotseatWidthPx; // not used in vertical bar layout
     public final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
@@ -551,6 +554,7 @@
         areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         numShownHotseatIcons =
                 isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        mHotseatColumnSpan = inv.numColumns;
 
         numShownAllAppsColumns =
                 isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
@@ -818,8 +822,7 @@
                     - hotseatBorderSpace * numShownHotseatIcons
                     - iconExtraSpacePx;
         } else {
-            int columns = inv.hotseatColumnSpan[mTypeIndex];
-            return getIconToIconWidthForColumns(columns) - iconExtraSpacePx;
+            return getIconToIconWidthForColumns(mHotseatColumnSpan) - iconExtraSpacePx;
         }
     }
 
@@ -890,10 +893,31 @@
     public void recalculateHotseatWidthAndBorderSpace() {
         if (!mIsScalableGrid) return;
 
-        int columns = inv.hotseatColumnSpan[mTypeIndex];
-        float hotseatWidthPx = getIconToIconWidthForColumns(columns);
-        hotseatBorderSpace = calculateHotseatBorderSpace(hotseatWidthPx, /* numExtraBorder= */ 0);
+        updateHotseatWidthAndBorderSpace(inv.numColumns);
+        int numWorkspaceColumns = getPanelCount() * inv.numColumns;
+        if (isTwoPanels) {
+            updateHotseatWidthAndBorderSpace(inv.numDatabaseHotseatIcons);
+            // If hotseat doesn't fit with current width, increase column span to fit by multiple
+            // of 2.
+            while (hotseatBorderSpace < mMinHotseatIconSpacePx
+                    && mHotseatColumnSpan < numWorkspaceColumns) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan + 2);
+            }
+        }
+        if (isQsbInline) {
+            // If QSB is inline, reduce column span until it fits.
+            int maxHotseatWidthAllowedPx = getIconToIconWidthForColumns(numWorkspaceColumns);
+            int minHotseatWidthRequiredPx =
+                    mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            while (minHotseatWidthRequiredPx > maxHotseatWidthAllowedPx
+                    && mHotseatColumnSpan > 1) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan - 1);
+                minHotseatWidthRequiredPx =
+                        mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            }
+        }
         hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace);
+
         // Spaces should be correct when the nav buttons are not inline
         if (!areNavButtonsInline) {
             return;
@@ -935,6 +959,12 @@
         } while (hotseatBorderSpace < mMinHotseatIconSpacePx && numShownHotseatIcons > 1);
     }
 
+    private void updateHotseatWidthAndBorderSpace(int columns) {
+        mHotseatColumnSpan = columns;
+        mHotseatWidthPx = getIconToIconWidthForColumns(mHotseatColumnSpan);
+        hotseatBorderSpace = calculateHotseatBorderSpace(mHotseatWidthPx, /* numExtraBorder= */ 0);
+    }
+
     private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) {
         return getCellLayoutBorderSpace(idp, 1f);
     }
@@ -958,6 +988,16 @@
         return mInfo;
     }
 
+    @VisibleForTesting
+    public int getHotseatColumnSpan() {
+        return mHotseatColumnSpan;
+    }
+
+    @VisibleForTesting
+    public int getHotseatWidthPx() {
+        return mHotseatWidthPx;
+    }
+
     public Builder toBuilder(Context context) {
         WindowBounds bounds = new WindowBounds(
                 widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
@@ -2120,7 +2160,8 @@
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
-        writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
+        writer.println(prefix + "\tmHotseatColumnSpan: " + mHotseatColumnSpan);
+        writer.println(prefix + pxToDpStr("mHotseatWidthPx", mHotseatWidthPx));
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
         writer.println(prefix + pxToDpStr("hotseatBarBottomSpacePx", hotseatBarBottomSpacePx));
         writer.println(prefix + pxToDpStr("mHotseatBarEdgePaddingPx",
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 51c7a05..eff748a 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -155,7 +155,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      * <p>Override in each subclass of this base class.
      */
-    public abstract String scrollToPositionAtProgress(float touchFraction);
+    public abstract CharSequence scrollToPositionAtProgress(float touchFraction);
 
     /**
      * Updates the bounds for the scrollbar.
@@ -193,14 +193,4 @@
         }
         scrollToPosition(0);
     }
-
-    /**
-     * Scrolls this recycler view to the bottom with easing and duration.
-     */
-    public void scrollToBottomWithMotion(int duration) {
-        if (mScrollbar != null) {
-            mScrollbar.reattachThumbToScroll();
-        }
-        smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, duration);
-    }
 }
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index bc36336..54aea38 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
 import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
@@ -59,6 +60,7 @@
 import com.android.launcher3.util.LockedUserState;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Partner;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.WindowManagerProxy;
 
@@ -75,7 +77,7 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-public class InvariantDeviceProfile {
+public class InvariantDeviceProfile implements SafeCloseable {
 
     public static final String TAG = "IDP";
     // We do not need any synchronization for this variable as its only written on UI thread.
@@ -163,7 +165,6 @@
      */
     public int numDatabaseHotseatIcons;
 
-    public int[] hotseatColumnSpan;
     public float[] hotseatBarBottomSpace;
     public float[] hotseatQsbSpace;
 
@@ -230,14 +231,14 @@
         if (!newGridName.equals(gridName)) {
             LauncherPrefs.get(context).put(GRID_NAME, newGridName);
         }
-        LockedUserState.get(context).runOnUserUnlocked(() -> {
-            new DeviceGridState(this).writeToPrefs(context);
-        });
+        LockedUserState.get(context).runOnUserUnlocked(() ->
+            new DeviceGridState(this).writeToPrefs(context));
 
         DisplayController.INSTANCE.get(context).setPriorityListener(
                 (displayContext, info, flags) -> {
                     if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
-                            | CHANGE_NAVIGATION_MODE | CHANGE_TASKBAR_PINNING)) != 0) {
+                            | CHANGE_NAVIGATION_MODE | CHANGE_TASKBAR_PINNING
+                            | CHANGE_DESKTOP_MODE)) != 0) {
                         onConfigChanged(displayContext);
                     }
                 });
@@ -263,7 +264,7 @@
 
         // Get the display info based on default display and interpolate it to existing display
         Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
-        @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
+        @DeviceType int defaultDeviceType = defaultInfo.getDeviceType();
         DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
                 defaultInfo,
                 getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
@@ -272,7 +273,7 @@
 
         Context displayContext = context.createDisplayContext(display);
         Info myInfo = new Info(displayContext);
-        @DeviceType int deviceType = getDeviceType(myInfo);
+        @DeviceType int deviceType = myInfo.getDeviceType();
         DisplayOption myDisplayOption = invDistWeightedInterpolate(
                 myInfo,
                 getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -296,6 +297,11 @@
         initGrid(context, myInfo, result, deviceType);
     }
 
+    @Override
+    public void close() {
+        DisplayController.INSTANCE.executeIfCreated(dc -> dc.setPriorityListener(null));
+    }
+
     /**
      * Reinitialize the current grid after a restore, where some grids might now be disabled.
      */
@@ -325,30 +331,13 @@
         }
     }
 
-    private static @DeviceType int getDeviceType(Info displayInfo) {
-        int flagPhone = 1 << 0;
-        int flagTablet = 1 << 1;
-
-        int type = displayInfo.supportedBounds.stream()
-                .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
-                .reduce(0, (a, b) -> a | b);
-        if (type == (flagPhone | flagTablet)) {
-            // device has profiles supporting both phone and table modes
-            return TYPE_MULTI_DISPLAY;
-        } else if (type == flagTablet) {
-            return TYPE_TABLET;
-        } else {
-            return TYPE_PHONE;
-        }
-    }
-
     public static String getCurrentGridName(Context context) {
         return LauncherPrefs.get(context).get(GRID_NAME);
     }
 
     private String initGrid(Context context, String gridName) {
         Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
-        @DeviceType int deviceType = getDeviceType(displayInfo);
+        @DeviceType int deviceType = displayInfo.getDeviceType();
 
         ArrayList<DisplayOption> allOptions =
                 getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -429,7 +418,6 @@
         numShownHotseatIcons = closestProfile.numHotseatIcons;
         numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
-        hotseatColumnSpan = closestProfile.hotseatColumnSpan;
         hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace;
         hotseatQsbSpace = displayOption.hotseatQsbSpace;
 
@@ -879,8 +867,6 @@
         private final int numHotseatIcons;
         private final int numDatabaseHotseatIcons;
 
-        private final int[] hotseatColumnSpan = new int[COUNT_SIZES];
-
         private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
 
         private @DimenRes int inlineNavButtonsEndSpacing;
@@ -931,17 +917,6 @@
             numDatabaseHotseatIcons = a.getInt(
                     R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
 
-            hotseatColumnSpan[INDEX_DEFAULT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpan, numColumns);
-            hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanLandscape, numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelLandscape,
-                    numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelPortrait,
-                    numColumns);
-
             inlineNavButtonsEndSpacing =
                     a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
                             R.dimen.taskbar_button_margin_default);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c91d4d0..b89d05e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.Flags.enableAddAppWidgetViaConfigActivityV2;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.Flags.enableWorkspaceInflation;
 import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
@@ -66,7 +67,6 @@
 import static com.android.launcher3.LauncherState.NO_SCALE;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
 import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
@@ -96,7 +96,9 @@
 import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
 import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
 import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.testing.shared.TestProtocol.CLOCK_ICON_DRAWABLE_LEAKING;
 import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
 import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
@@ -421,6 +423,7 @@
     @Override
     @TargetApi(Build.VERSION_CODES.S)
     protected void onCreate(Bundle savedInstanceState) {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onCreate: instance=" + this);
         mStartupLatencyLogger = createStartupLatencyLogger(
                 sIsNewProcess
                         ? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
@@ -1079,6 +1082,7 @@
 
     @Override
     protected void onStart() {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onStart: instance=" + this);
         TraceHelper.INSTANCE.beginSection(ON_START_EVT);
         super.onStart();
         if (!mDeferOverlayCallbacks) {
@@ -1092,6 +1096,7 @@
     @Override
     @CallSuper
     protected void onDeferredResumed() {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDeferredResumed: instance=" + this);
         logStopAndResume(true /* isResume */);
 
         // Process any items that were added while Launcher was away.
@@ -1261,6 +1266,13 @@
             getAllAppsExitEvent().ifPresent(getStatsLogManager().logger()::log);
             mAllAppsSessionLogId = null;
         }
+
+        // Set screen title for Talkback
+        if (state == ALL_APPS) {
+            setTitle(R.string.all_apps_label);
+        } else {
+            setTitle(R.string.home_screen);
+        }
     }
 
     /**
@@ -1272,6 +1284,7 @@
 
     @Override
     protected void onResume() {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onResume: instance=" + this);
         TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
         super.onResume();
 
@@ -1287,6 +1300,7 @@
 
     @Override
     protected void onPause() {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onPause: instance=" + this);
         // Ensure that items added to Launcher are queued until Launcher returns
         ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
 
@@ -1361,7 +1375,7 @@
         // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
         // default state, otherwise we will update to the wrong offsets in RTL
         mWorkspace.lockWallpaperToDefaultPage();
-        if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+        if (!enableSmartspaceRemovalToggle()) {
             mWorkspace.bindAndInitFirstWorkspaceScreen();
         }
         mDragController.addDragListener(mWorkspace);
@@ -1701,7 +1715,7 @@
         AbstractFloatingView.closeAllOpenViews(this);
         getStateManager().goToState(ALL_APPS, alreadyOnHome);
         if (mAppsView.isSearching()) {
-            mAppsView.reset(alreadyOnHome);
+            mAppsView.getSearchUiManager().resetSearch();
         }
         if (mAppsView.getCurrentPage() != tab) {
             mAppsView.switchToTab(tab);
@@ -1769,6 +1783,7 @@
 
     @Override
     public void onDestroy() {
+        testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDestroy: instance=" + this);
         super.onDestroy();
         ACTIVITY_TRACKER.onActivityDestroyed(this);
 
@@ -2508,7 +2523,13 @@
         final int itemCount = container.getChildCount();
         for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
             View item = container.getChildAt(itemIdx);
-            if (op.test((ItemInfo) item.getTag())) {
+            if (item instanceof ViewGroup viewGroup) {
+                View view = mapOverViewGroup(viewGroup, op);
+                if (view != null) {
+                    return view;
+                }
+            }
+            if (item.getTag() instanceof ItemInfo itemInfo && op.test(itemInfo)) {
                 return item;
             }
         }
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index c20f323..6a9d170 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -220,17 +220,28 @@
 
     /**
      * Utility method to create an {@link AnimatorListener} which executes a callback on animation
-     * cancel.
+     * cancel. Once the cancel has been dispatched, this listener will no longer be called.
      */
-    public static AnimatorListener newCancelListener(Runnable callback) {
-        return new AnimatorListenerAdapter() {
+    public static AnimatorListener newSingleUseCancelListener(Runnable callback) {
+        return newCancelListener(callback, true);
+    }
 
+    /**
+     * Utility method to create an {@link AnimatorListener} which executes a callback on animation
+     * cancel.
+     *
+     * @param isSingleUse {@code true} means the callback will be called at most once
+     */
+    public static AnimatorListener newCancelListener(Runnable callback, boolean isSingleUse) {
+        return new AnimatorListenerAdapter() {
             boolean mDispatched = false;
 
             @Override
             public void onAnimationCancel(Animator animation) {
                 if (!mDispatched) {
-                    mDispatched = true;
+                    if (isSingleUse) {
+                        mDispatched = true;
+                    }
                     callback.run();
                 }
             }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 50a597d..a4ae1c8 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -19,9 +19,9 @@
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
 import static android.content.Context.RECEIVER_EXPORTED;
 
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.LauncherPrefs.ICON_STATE;
 import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
@@ -52,6 +52,7 @@
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.LockedUserState;
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SafeCloseable;
@@ -78,14 +79,10 @@
 
     private final RunnableList mOnTerminateCallback = new RunnableList();
 
-    public static LauncherAppState getInstance(final Context context) {
+    public static LauncherAppState getInstance(Context context) {
         return INSTANCE.get(context);
     }
 
-    public static LauncherAppState getInstanceNoCreate() {
-        return INSTANCE.getNoCreate();
-    }
-
     public Context getContext() {
         return mContext;
     }
@@ -130,7 +127,7 @@
                 .addUserEventListener(mModel::onUserEvent);
         mOnTerminateCallback.add(userChangeListener::close);
 
-        if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+        if (enableSmartspaceRemovalToggle()) {
             OnSharedPreferenceChangeListener firstPagePinnedItemListener =
                     new OnSharedPreferenceChangeListener() {
                         @Override
@@ -185,7 +182,7 @@
         mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
                 iconCacheFileName, mIconProvider);
         mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
-                iconCacheFileName != null);
+                PackageManagerHelper.INSTANCE.get(context), iconCacheFileName != null);
         mOnTerminateCallback.add(mIconCache::close);
         mOnTerminateCallback.add(mModel::destroy);
     }
@@ -210,7 +207,7 @@
     }
 
     private void refreshAndReloadLauncher() {
-        LauncherIcons.clearPool();
+        LauncherIcons.clearPool(mContext);
         mIconCache.updateIconParams(
                 mInvariantDeviceProfile.fillResIconDpi, mInvariantDeviceProfile.iconBitmapSize);
         mModel.forceReload();
@@ -261,7 +258,7 @@
 
         @Override
         public void onSystemIconStateChanged(String iconState) {
-            IconShape.init(mContext);
+            IconShape.INSTANCE.get(mContext).pickBestShape(mContext);
             refreshAndReloadLauncher();
             LauncherPrefs.get(mContext).put(ICON_STATE, iconState);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 7fdfd72..e3da389 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -48,7 +48,6 @@
 import com.android.launcher3.model.AddWorkspaceItemsTask;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseLauncherBinder;
-import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.CacheDataUpdatedTask;
@@ -57,6 +56,7 @@
 import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.model.ModelDelegate;
 import com.android.launcher3.model.ModelLauncherCallbacks;
+import com.android.launcher3.model.ModelTaskController;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.PackageInstallStateChangedTask;
 import com.android.launcher3.model.PackageUpdatedTask;
@@ -82,7 +82,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.CancellationException;
-import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
@@ -99,6 +98,8 @@
     @NonNull
     private final LauncherAppState mApp;
     @NonNull
+    private final PackageManagerHelper mPmHelper;
+    @NonNull
     private final ModelDbController mModelDbController;
     @NonNull
     private final Object mLock = new Object();
@@ -153,12 +154,13 @@
 
     LauncherModel(@NonNull final Context context, @NonNull final LauncherAppState app,
             @NonNull final IconCache iconCache, @NonNull final AppFilter appFilter,
-            final boolean isPrimaryInstance) {
+            @NonNull final PackageManagerHelper pmHelper, final boolean isPrimaryInstance) {
         mApp = app;
+        mPmHelper = pmHelper;
         mModelDbController = new ModelDbController(context);
         mBgAllAppsList = new AllAppsList(iconCache, appFilter);
-        mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
-                isPrimaryInstance);
+        mModelDelegate = ModelDelegate.newInstance(context, app, mPmHelper, mBgAllAppsList,
+                mBgDataModel, isPrimaryInstance);
     }
 
     @NonNull
@@ -426,13 +428,9 @@
     @Override
     public void onInstallSessionCreated(@NonNull final PackageInstallInfo sessionInfo) {
         if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
-            enqueueModelUpdateTask(new BaseModelUpdateTask() {
-                @Override
-                public void execute(@NonNull final LauncherAppState app,
-                        @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                    apps.addPromiseApp(app.getContext(), sessionInfo);
-                    bindApplicationsIfNeeded();
-                }
+            enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+                apps.addPromiseApp(mApp.getContext(), sessionInfo);
+                taskController.bindApplicationsIfNeeded();
             });
         }
     }
@@ -440,60 +438,56 @@
     @Override
     public void onSessionFailure(@NonNull final String packageName,
             @NonNull final UserHandle user) {
-        enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(@NonNull final LauncherAppState app,
-                    @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                IconCache iconCache = app.getIconCache();
-                final IntSet removedIds = new IntSet();
-                HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
-                boolean isAppArchived = new PackageManagerHelper(
-                        mApp.getContext()).isAppArchivedForUser(packageName, user);
-                synchronized (dataModel) {
-                    if (isAppArchived) {
-                        // Remove package icon cache entry for archived app in case of a session
-                        // failure.
-                        mApp.getIconCache().remove(
-                                new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
-                                user);
-                    }
+        enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+            IconCache iconCache = mApp.getIconCache();
+            final IntSet removedIds = new IntSet();
+            HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
+            boolean isAppArchived = PackageManagerHelper.INSTANCE.get(mApp.getContext())
+                    .isAppArchivedForUser(packageName, user);
+            synchronized (dataModel) {
+                if (isAppArchived) {
+                    // Remove package icon cache entry for archived app in case of a session
+                    // failure.
+                    mApp.getIconCache().remove(
+                            new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                            user);
+                }
 
-                    for (ItemInfo info : dataModel.itemsIdMap) {
-                        if (info instanceof WorkspaceItemInfo
-                                && ((WorkspaceItemInfo) info).hasPromiseIconUi()
-                                && user.equals(info.user)
-                                && info.getIntent() != null) {
-                            if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
-                                removedIds.add(info.id);
-                            }
-                            if (((WorkspaceItemInfo) info).isArchived()) {
-                                WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
-                                // Refresh icons on the workspace for archived apps.
-                                iconCache.getTitleAndIcon(workspaceItem,
-                                        workspaceItem.usingLowResIcon());
-                                archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
-                            }
+                for (ItemInfo info : dataModel.itemsIdMap) {
+                    if (info instanceof WorkspaceItemInfo
+                            && ((WorkspaceItemInfo) info).hasPromiseIconUi()
+                            && user.equals(info.user)
+                            && info.getIntent() != null) {
+                        if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+                            removedIds.add(info.id);
+                        }
+                        if (((WorkspaceItemInfo) info).isArchived()) {
+                            WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
+                            // Refresh icons on the workspace for archived apps.
+                            iconCache.getTitleAndIcon(workspaceItem,
+                                    workspaceItem.usingLowResIcon());
+                            archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
                         }
                     }
-
-                    if (isAppArchived) {
-                        apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
-                    }
                 }
 
-                if (!removedIds.isEmpty()) {
-                    deleteAndBindComponentsRemoved(
-                            ItemInfoMatcher.ofItemIds(removedIds),
-                            "removed because install session failed");
-                }
-                if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
-                    bindUpdatedWorkspaceItems(
-                            archivedWorkspaceItemsToCacheRefresh.stream().toList());
-                }
                 if (isAppArchived) {
-                    bindApplicationsIfNeeded();
+                    apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
                 }
             }
+
+            if (!removedIds.isEmpty()) {
+                taskController.deleteAndBindComponentsRemoved(
+                        ItemInfoMatcher.ofItemIds(removedIds),
+                        "removed because install session failed");
+            }
+            if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
+                taskController.bindUpdatedWorkspaceItems(
+                        archivedWorkspaceItemsToCacheRefresh.stream().toList());
+            }
+            if (isAppArchived) {
+                taskController.bindApplicationsIfNeeded();
+            }
         });
     }
 
@@ -583,13 +577,9 @@
      */
     public void onWidgetLabelsUpdated(@NonNull final HashSet<String> updatedPackages,
             @NonNull final UserHandle user) {
-        enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(@NonNull final LauncherAppState app,
-                    @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, app);
-                bindUpdatedWidgets(dataModel);
-            }
+        enqueueModelUpdateTask((taskController, dataModel, apps) ->  {
+            dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, mApp);
+            taskController.bindUpdatedWidgets(dataModel);
         });
     }
 
@@ -597,8 +587,15 @@
         if (mModelDestroyed) {
             return;
         }
-        task.init(mApp, this, mBgDataModel, mBgAllAppsList, MAIN_EXECUTOR);
-        MODEL_EXECUTOR.execute(task);
+        MODEL_EXECUTOR.execute(() -> {
+            if (!isModelLoaded()) {
+                // Loader has not yet run.
+                return;
+            }
+            ModelTaskController controller = new ModelTaskController(
+                    mApp, mBgDataModel, mBgAllAppsList, this, MAIN_EXECUTOR);
+            task.execute(controller, mBgDataModel, mBgAllAppsList);
+        });
     }
 
     /**
@@ -610,18 +607,10 @@
         void execute(@NonNull Callbacks callbacks);
     }
 
-    /**
-     * A runnable which changes/updates the data model of the launcher based on certain events.
-     */
-    public interface ModelUpdateTask extends Runnable {
+    public interface ModelUpdateTask {
 
-        /**
-         * Called before the task is posted to initialize the internal state.
-         */
-        void init(@NonNull LauncherAppState app, @NonNull LauncherModel model,
-                @NonNull BgDataModel dataModel, @NonNull AllAppsList allAppsList,
-                @NonNull Executor uiExecutor);
-
+        void execute(@NonNull ModelTaskController taskController,
+                @NonNull BgDataModel dataModel, @NonNull AllAppsList apps);
     }
 
     public void updateAndBindWorkspaceItem(@NonNull final WorkspaceItemInfo si,
@@ -638,27 +627,19 @@
      */
     public void updateAndBindWorkspaceItem(
             @NonNull final Supplier<WorkspaceItemInfo> itemProvider) {
-        enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(@NonNull final LauncherAppState app,
-                    @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                WorkspaceItemInfo info = itemProvider.get();
-                getModelWriter().updateItemInDatabase(info);
-                ArrayList<WorkspaceItemInfo> update = new ArrayList<>();
-                update.add(info);
-                bindUpdatedWorkspaceItems(update);
-            }
+        enqueueModelUpdateTask((taskController, dataModel, apps) ->  {
+            WorkspaceItemInfo info = itemProvider.get();
+            taskController.getModelWriter().updateItemInDatabase(info);
+            ArrayList<WorkspaceItemInfo> update = new ArrayList<>();
+            update.add(info);
+            taskController.bindUpdatedWorkspaceItems(update);
         });
     }
 
     public void refreshAndBindWidgetsAndShortcuts(@Nullable final PackageUserKey packageUser) {
-        enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(@NonNull final LauncherAppState app,
-                    @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                dataModel.widgetsModel.update(app, packageUser);
-                bindUpdatedWidgets(dataModel);
-            }
+        enqueueModelUpdateTask((taskController, dataModel, apps) ->  {
+            dataModel.widgetsModel.update(taskController.getApp(), packageUser);
+            taskController.bindUpdatedWidgets(dataModel);
         });
     }
 
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 875c407..13181e8 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -19,7 +19,6 @@
 import android.content.Context.MODE_PRIVATE
 import android.content.SharedPreferences
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
 import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
@@ -31,16 +30,15 @@
 import com.android.launcher3.states.RotationHelper
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.SafeCloseable
 import com.android.launcher3.util.Themes
 
 /**
  * Use same context for shared preferences, so that we use a single cached instance
  *
  * TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
- * TODO(b/274501660): Fix ReorderWidgets#simpleReorder test before enabling
- *   isBootAwareStartupDataEnabled
  */
-class LauncherPrefs(private val encryptedContext: Context) {
+class LauncherPrefs(private val encryptedContext: Context) : SafeCloseable {
     private val deviceProtectedStorageContext =
         encryptedContext.createDeviceProtectedStorageContext()
 
@@ -51,22 +49,8 @@
     private val Item.encryptedPrefs
         get() = encryptedContext.getSharedPreferences(sharedPrefFile, MODE_PRIVATE)
 
-    // This call to `SharedPreferences` needs to be explicit rather than using `get` since doing so
-    // would result in a circular dependency between `isStartupDataMigrated` and `choosePreferences`
-    val isStartupDataMigrated: Boolean
-        get() =
-            bootAwarePrefs.getBoolean(
-                IS_STARTUP_DATA_MIGRATED.sharedPrefKey,
-                IS_STARTUP_DATA_MIGRATED.defaultValue
-            )
-
     private fun chooseSharedPreferences(item: Item): SharedPreferences =
-        if (
-            (moveStartupDataToDeviceProtectedStorageIsEnabled &&
-                item.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                isStartupDataMigrated) || item.encryptionType == EncryptionType.DEVICE_PROTECTED
-        )
-            bootAwarePrefs
+        if (item.encryptionType == EncryptionType.DEVICE_PROTECTED) bootAwarePrefs
         else item.encryptedPrefs
 
     /** Wrapper around `getInner` for a `ContextualItem` */
@@ -146,11 +130,7 @@
                 .toMutableMap()
 
         val bootAwareUpdates =
-            updates.filter {
-                (it.first.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
-                    it.first.encryptionType == EncryptionType.DEVICE_PROTECTED
-            }
+            updates.filter { it.first.encryptionType == EncryptionType.DEVICE_PROTECTED }
         if (bootAwareUpdates.isNotEmpty()) {
             updatesPerPrefFile[bootAwarePrefs] = bootAwareUpdates
         }
@@ -251,12 +231,7 @@
                 .groupBy { it.encryptedPrefs }
                 .toMutableMap()
 
-        val bootAwareUpdates =
-            items.filter {
-                (it.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
-                    it.encryptionType == EncryptionType.DEVICE_PROTECTED
-            }
+        val bootAwareUpdates = items.filter { it.encryptionType == EncryptionType.DEVICE_PROTECTED }
         if (bootAwareUpdates.isNotEmpty()) {
             itemsPerFile[bootAwarePrefs] = bootAwareUpdates
         }
@@ -268,24 +243,9 @@
         }
     }
 
-    fun migrateStartupDataToDeviceProtectedStorage() {
-        if (!moveStartupDataToDeviceProtectedStorageIsEnabled) return
-
-        Log.d(
-            TAG,
-            "Migrating data to unencrypted shared preferences to enable preloading " +
-                "while the user is locked the next time the device reboots."
-        )
-
-        with(bootAwarePrefs.edit()) {
-            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.forEach { putValue(it, get(it)) }
-            putBoolean(IS_STARTUP_DATA_MIGRATED.sharedPrefKey, true)
-            apply()
-        }
-    }
+    override fun close() {}
 
     companion object {
-        private const val TAG = "LauncherPrefs"
         @VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
 
         @JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) }
@@ -293,46 +253,39 @@
         @JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context)
 
         const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
+        const val TASKBAR_PINNING_DESKTOP_MODE_KEY = "TASKBAR_PINNING_DESKTOP_MODE_KEY"
         const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
         @JvmField
-        val ICON_STATE =
-            nonRestorableItem("pref_icon_shape_path", "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+        val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)
 
         @JvmField
         val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
         @JvmField
-        val THEMED_ICONS =
-            backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+        val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
         @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
         @JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
         @JvmField
         val WORKSPACE_SIZE =
-            backedUpItem(
-                DeviceGridState.KEY_WORKSPACE_SIZE,
-                "",
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+            backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", EncryptionType.ENCRYPTED)
         @JvmField
         val HOTSEAT_COUNT =
-            backedUpItem(
-                DeviceGridState.KEY_HOTSEAT_COUNT,
-                -1,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+            backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, EncryptionType.ENCRYPTED)
         @JvmField
         val TASKBAR_PINNING =
             backedUpItem(TASKBAR_PINNING_KEY, false, EncryptionType.DEVICE_PROTECTED)
+        @JvmField
+        val TASKBAR_PINNING_IN_DESKTOP_MODE =
+            backedUpItem(TASKBAR_PINNING_DESKTOP_MODE_KEY, true, EncryptionType.DEVICE_PROTECTED)
 
         @JvmField
         val DEVICE_TYPE =
             backedUpItem(
                 DeviceGridState.KEY_DEVICE_TYPE,
                 InvariantDeviceProfile.TYPE_PHONE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.ENCRYPTED
             )
         @JvmField
-        val DB_FILE =
-            backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+        val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.ENCRYPTED)
         @JvmField
         val SHOULD_SHOW_SMARTSPACE =
             backedUpItem(
@@ -345,15 +298,11 @@
             backedUpItem(
                 RestoreDbTask.RESTORED_DEVICE_TYPE,
                 InvariantDeviceProfile.TYPE_PHONE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.ENCRYPTED
             )
         @JvmField
         val IS_FIRST_LOAD_AFTER_RESTORE =
-            nonRestorableItem(
-                FIRST_LOAD_AFTER_RESTORE_KEY,
-                false,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+            nonRestorableItem(FIRST_LOAD_AFTER_RESTORE_KEY, false, EncryptionType.ENCRYPTED)
         @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
         @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
         @JvmField
@@ -362,7 +311,7 @@
                 "idp_grid_name",
                 isBackedUp = true,
                 defaultValue = null,
-                encryptionType = EncryptionType.MOVE_TO_DEVICE_PROTECTED,
+                encryptionType = EncryptionType.ENCRYPTED,
                 type = String::class.java
             )
         @JvmField
@@ -370,24 +319,11 @@
             backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
                 RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
             }
-        @JvmField
-        val IS_STARTUP_DATA_MIGRATED =
-            ConstantItem(
-                "is_startup_data_boot_aware",
-                isBackedUp = false,
-                defaultValue = false,
-                encryptionType = EncryptionType.DEVICE_PROTECTED
-            )
 
         // Preferences for widget configurations
         @JvmField
         val RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
             backedUpItem("launcher.reconfigurable_widget_education_tip_seen", false)
-        @JvmField
-        val WIDGETS_EDUCATION_DIALOG_SEEN =
-            backedUpItem("launcher.widgets_education_dialog_seen", false)
-        @JvmField
-        val WIDGETS_EDUCATION_TIP_SEEN = backedUpItem("launcher.widgets_education_tip_seen", false)
 
         @JvmStatic
         fun <T> backedUpItem(
@@ -442,12 +378,6 @@
     }
 }
 
-// It is a var because the unit tests are setting this to true so they can run.
-var moveStartupDataToDeviceProtectedStorageIsEnabled: Boolean =
-    com.android.launcher3.config.FeatureFlags.MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE.get()
-
-private val ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE: MutableSet<ConstantItem<*>> = mutableSetOf()
-
 abstract class Item {
     abstract val sharedPrefKey: String
     abstract val isBackedUp: Boolean
@@ -467,14 +397,6 @@
     // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
     override val type: Class<out T> = defaultValue!!::class.java
 ) : Item() {
-    init {
-        if (
-            encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                moveStartupDataToDeviceProtectedStorageIsEnabled
-        ) {
-            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.add(this)
-        }
-    }
 
     fun get(c: Context): T = LauncherPrefs.get(c).get(this)
 }
@@ -501,5 +423,4 @@
 enum class EncryptionType {
     ENCRYPTED,
     DEVICE_PROTECTED,
-    MOVE_TO_DEVICE_PROTECTED
 }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4e0ba62..6e2d357 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -48,11 +48,11 @@
      */
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
-        if (appState == null || !appState.getModel().isModelLoaded()) {
-            return;
-        }
-        appState.getModel().dumpState("", fd, writer, args);
+        LauncherAppState.INSTANCE.executeIfCreated(appState -> {
+            if (appState.getModel().isModelLoaded()) {
+                appState.getModel().dumpState("", fd, writer, args);
+            }
+        });
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 84b8ba1..87ac193 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -183,6 +183,7 @@
         public static final int CONTAINER_SHORTCUTS = -107;
         public static final int CONTAINER_SETTINGS = -108;
         public static final int CONTAINER_TASKSWITCHER = -109;
+        public static final int CONTAINER_PRIVATESPACE = -110;
 
         // Represents any of the extended containers implemented in non-AOSP variants.
         public static final int EXTENDED_CONTAINERS = -200;
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index 3d7e11e..9944ef6 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 
 import com.android.launcher3.graphics.BitmapCreationCheck;
-import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.util.ResourceBasedOverride;
 
@@ -36,7 +35,6 @@
 
     protected void init(Context context) {
         FileLog.setDir(context.getApplicationContext().getFilesDir());
-        IconShape.init(context);
 
         if (BitmapCreationCheck.ENABLED) {
             BitmapCreationCheck.startTracking(context);
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index f582be0..7d6d154 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -4,11 +4,12 @@
 import android.os.Build
 import android.os.Trace
 import androidx.annotation.UiThread
+import com.android.launcher3.Flags.enableSmartspaceRemovalToggle
 import com.android.launcher3.LauncherConstants.TraceEvents
+import com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET
 import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
 import com.android.launcher3.allapps.AllAppsStore
 import com.android.launcher3.config.FeatureFlags
-import com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget
 import com.android.launcher3.model.BgDataModel
 import com.android.launcher3.model.StringCache
 import com.android.launcher3.model.data.AppInfo
@@ -34,7 +35,7 @@
     var pagesToBindSynchronously = LIntSet()
 
     private var isFirstPagePinnedItemEnabled =
-        (BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get())
+        (BuildConfig.QSB_ON_FIRST_SCREEN && !enableSmartspaceRemovalToggle())
 
     var stringCache: StringCache? = null
 
@@ -314,16 +315,16 @@
         )
         val firstScreenPosition = 0
         if (
-            (FeatureFlags.QSB_ON_FIRST_SCREEN &&
-                isFirstPagePinnedItemEnabled &&
-                !shouldShowFirstPageWidget()) &&
+            (isFirstPagePinnedItemEnabled &&
+                !SHOULD_SHOW_FIRST_PAGE_WIDGET) &&
                 orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition
         ) {
             orderedScreenIds.removeValue(FIRST_SCREEN_ID)
             orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID)
         } else if (
-            (!FeatureFlags.QSB_ON_FIRST_SCREEN && !isFirstPagePinnedItemEnabled ||
-                shouldShowFirstPageWidget()) && orderedScreenIds.isEmpty
+            (!isFirstPagePinnedItemEnabled ||
+                    SHOULD_SHOW_FIRST_PAGE_WIDGET)
+            && orderedScreenIds.isEmpty
         ) {
             // If there are no screens, we need to have an empty screen
             launcher.workspace.addExtraEmptyScreens()
@@ -379,9 +380,8 @@
         }
         orderedScreenIds
             .filterNot { screenId ->
-                FeatureFlags.QSB_ON_FIRST_SCREEN &&
                     isFirstPagePinnedItemEnabled &&
-                    !FeatureFlags.shouldShowFirstPageWidget() &&
+                    !SHOULD_SHOW_FIRST_PAGE_WIDGET &&
                     screenId == WorkspaceLayoutManager.FIRST_SCREEN_ID
             }
             .forEach { screenId ->
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 1c23644..365fbd3 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -485,7 +485,10 @@
         super.onVisibilityAggregated(isVisible);
     }
 
-    protected boolean isPageInTransition() {
+    /**
+     * Returns true if the page is in the middle of transition to another page
+     */
+    public boolean isPageInTransition() {
         return mIsPageInTransition;
     }
 
@@ -785,7 +788,7 @@
         if (mScroller.isFinished() && pageScrollChanged) {
             // TODO(b/246283207): Remove logging once root cause of flake detected.
             if (Utilities.isRunningInTestHarness() && !(this instanceof Workspace)) {
-                Log.d("b/246283207", this.getClass().getSimpleName() + "#onLayout() -> "
+                Log.d("b/246283207", TAG + "#onLayout() -> "
                         + "if(mScroller.isFinished() && pageScrollChanged) -> getNextPage(): "
                         + getNextPage() + ", getScrollForPage(getNextPage()): "
                         + getScrollForPage(getNextPage()));
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 1362586..0a4fb73 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -362,7 +362,7 @@
 
         public void onLauncherResume() {
             // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
-            if (new PackageManagerHelper(mContext).getApplicationInfo(mPackageName,
+            if (PackageManagerHelper.INSTANCE.get(mContext).getApplicationInfo(mPackageName,
                     mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
                 mDragObject.dragSource = mOriginal;
                 mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2b886e4..4a26a18 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,6 +18,8 @@
 
 import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
 
+import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -68,6 +70,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
 import androidx.annotation.ChecksSdkIntAtLeast;
@@ -102,6 +105,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -130,6 +134,10 @@
     @ChecksSdkIntAtLeast(api = VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "U")
     public static final boolean ATLEAST_U = Build.VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE;
 
+    @ChecksSdkIntAtLeast(api = VERSION_CODES.VANILLA_ICE_CREAM, codename = "V")
+    public static final boolean ATLEAST_V = Build.VERSION.SDK_INT
+            >= VERSION_CODES.VANILLA_ICE_CREAM;
+
     /**
      * Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
      */
@@ -148,6 +156,9 @@
     public static final int TRANSLATE_LEFT = 2;
     public static final int TRANSLATE_RIGHT = 3;
 
+    public static final boolean SHOULD_SHOW_FIRST_PAGE_WIDGET =
+            enableSmartspaceAsAWidget() && WIDGET_ON_FIRST_SCREEN;
+
     @IntDef({TRANSLATE_UP, TRANSLATE_DOWN, TRANSLATE_LEFT, TRANSLATE_RIGHT})
     public @interface AdjustmentDirection{}
 
@@ -830,4 +841,27 @@
                 // No-Op
         }
     }
+
+    /**
+     * Does a depth-first search through the View hierarchy starting at root, to find a view that
+     * matches the predicate. Returns null if no View was found. View has a findViewByPredicate
+     * member function but it is currently a @hide API.
+     */
+    @Nullable
+    public static <T extends View> T findViewByPredicate(@NonNull View root,
+            @NonNull Predicate<View> predicate) {
+        if (predicate.test(root)) {
+            return (T) root;
+        }
+        if (root instanceof ViewGroup parent) {
+            int count = parent.getChildCount();
+            for (int i = 0; i < count; i++) {
+                View view = findViewByPredicate(parent.getChildAt(i), predicate);
+                if (view != null) {
+                    return (T) view;
+                }
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0fc3211..584d089 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -28,10 +29,9 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
@@ -126,7 +126,6 @@
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.PendingAppWidgetHostView;
 import com.android.launcher3.widget.WidgetManagerHelper;
-import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
 import com.android.launcher3.widget.util.WidgetSizes;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
@@ -600,7 +599,7 @@
     public void bindAndInitFirstWorkspaceScreen() {
         if ((!FeatureFlags.QSB_ON_FIRST_SCREEN
                 || !mLauncher.getIsFirstPagePinnedItemEnabled())
-                || shouldShowFirstPageWidget()) {
+                || SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             mFirstPagePinnedItem = null;
             return;
         }
@@ -642,7 +641,7 @@
         mWorkspaceScreens.clear();
 
         // Ensure that the first page is always present
-        if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+        if (!enableSmartspaceRemovalToggle()) {
             bindAndInitFirstWorkspaceScreen();
         }
 
@@ -811,7 +810,7 @@
 
             // We don't want to remove the first screen even if it's empty because that's where
             // first page pinned item would go if it gets turned back on.
-            if (ENABLE_SMARTSPACE_REMOVAL.get() && screenId == FIRST_SCREEN_ID) {
+            if (enableSmartspaceRemovalToggle() && screenId == FIRST_SCREEN_ID) {
                 continue;
             }
 
@@ -1040,7 +1039,7 @@
             CellLayout cl = mWorkspaceScreens.valueAt(i);
             // FIRST_SCREEN_ID can never be removed.
             if (((!FeatureFlags.QSB_ON_FIRST_SCREEN
-                    || shouldShowFirstPageWidget())
+                    || SHOULD_SHOW_FIRST_PAGE_WIDGET)
                     || id > FIRST_SCREEN_ID)
                     && cl.getShortcutsAndWidgets().getChildCount() == 0) {
                 removeScreens.add(id);
@@ -1744,9 +1743,6 @@
 
         final DragView dv;
         if (contentView instanceof View) {
-            if (contentView instanceof LauncherAppWidgetHostView) {
-                mDragController.addDragListener(new AppWidgetHostViewDragListener(mLauncher));
-            }
             dv = mDragController.startDrag(
                     contentView,
                     draggableView,
@@ -1955,7 +1951,7 @@
                 // In order to keep everything continuous, we hand off the currently rendered
                 // folder background to the newly created icon. This preserves animation state.
                 fi.setFolderBackground(mFolderCreateBg);
-                mFolderCreateBg = new PreviewBackground();
+                mFolderCreateBg = new PreviewBackground(getContext());
                 fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale);
             } else {
                 fi.prepareCreateAnimation(v);
@@ -2670,7 +2666,7 @@
         boolean userFolderPending = willCreateUserFolder(info, mDragOverView, false);
         if (mDragMode == DRAG_MODE_NONE && userFolderPending) {
 
-            mFolderCreateBg = new PreviewBackground();
+            mFolderCreateBg = new PreviewBackground(getContext());
             mFolderCreateBg.setup(mLauncher, mLauncher, null,
                     mDragOverView.getMeasuredWidth(), mDragOverView.getPaddingTop());
 
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9792300..814d142 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -414,7 +414,7 @@
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
 
-                bindItem(item, accessibility, finishCallback);
+                bindItem(info, accessibility, finishCallback);
                 announceConfirmation(R.string.item_added_to_workspace);
             } else if (item instanceof PendingAddItemInfo) {
                 PendingAddItemInfo info = (PendingAddItemInfo) item;
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 8026d4a..0792641 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;
@@ -470,8 +471,9 @@
      * @param exitSearch Whether to force exit the search state and return to A-Z apps list.
      */
     public void reset(boolean animate, boolean exitSearch) {
+        // Scroll Main and Work RV to top. Search RV is done in `resetSearch`.
         for (int i = 0; i < mAH.size(); i++) {
-            if (mAH.get(i).mRecyclerView != null) {
+            if (i != SEARCH && mAH.get(i).mRecyclerView != null) {
                 mAH.get(i).mRecyclerView.scrollToTop();
             }
         }
@@ -485,10 +487,8 @@
         // Reset the base recycler view after transitioning home.
         updateHeaderScroll(0);
         if (exitSearch) {
-            // Reset the search bar after transitioning home.
+            // Reset the search bar and search RV after transitioning home.
             MAIN_EXECUTOR.getHandler().post(mSearchUiManager::resetSearch);
-            // Animate to A-Z with 0 time to reset the animation with proper state management.
-            animateToSearchState(false, 0);
         }
         if (isSearching()) {
             mWorkManager.reset();
@@ -499,18 +499,15 @@
      * Exits search and returns to A-Z apps list. Scroll to the private space header.
      */
     public void resetAndScrollToPrivateSpaceHeader() {
-        if (mTouchHandler != null) {
-            mTouchHandler.endFastScrolling();
-        }
-
-        // Reset the base recycler view after transitioning home.
-        updateHeaderScroll(0);
-
         // Animate to A-Z with 0 time to reset the animation with proper state management.
+        // We can't rely on `animateToSearchState` with delay inside `resetSearch` because that will
+        // conflict with following scrolling to bottom, so we need it with 0 time here.
         animateToSearchState(false, 0);
 
         MAIN_EXECUTOR.getHandler().post(() -> {
             // Reset the search bar after transitioning home.
+            // When `resetSearch` is called after `animateToSearchState` is finished, the inside
+            // `animateToSearchState` with delay is a just no-op and return early.
             mSearchUiManager.resetSearch();
             // Switch to the main tab
             switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 36a44cc..ba34f59 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -180,7 +180,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
     @Override
-    public String scrollToPositionAtProgress(float touchFraction) {
+    public CharSequence scrollToPositionAtProgress(float touchFraction) {
         int rowCount = mApps.getNumAppRows();
         if (rowCount == 0) {
             return "";
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 564daf1..1b0ad04 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -294,7 +294,9 @@
     private void onScaleProgressChanged() {
         final float scaleProgress = mAllAppScale.value;
         SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
-        mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+        if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+            mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+        }
 
         AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
 
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 4d4b8d2..a810331 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -22,6 +22,9 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT;
 
 import android.content.Context;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -65,11 +68,11 @@
      */
     public static class FastScrollSectionInfo {
         // The section name
-        public final String sectionName;
+        public final CharSequence sectionName;
         // The item position
         public final int position;
 
-        public FastScrollSectionInfo(String sectionName, int position) {
+        public FastScrollSectionInfo(CharSequence sectionName, int position) {
             this.sectionName = sectionName;
             this.position = position;
         }
@@ -93,6 +96,7 @@
 
     // The of ordered component names as a result of a search query
     private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
+    private final SpannableString mPrivateProfileAppScrollerBadge;
     private BaseAllAppsAdapter<T> mAdapter;
     private AppInfoComparator mAppNameComparator;
     private int mNumAppsPerRowAllApps;
@@ -110,6 +114,10 @@
         if (mAllAppsStore != null) {
             mAllAppsStore.addUpdateListener(this);
         }
+        mPrivateProfileAppScrollerBadge = new SpannableString(" ");
+        mPrivateProfileAppScrollerBadge.setSpan(new ImageSpan(context,
+                        R.drawable.ic_private_profile_app_scroller_badge, ImageSpan.ALIGN_CENTER),
+                0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
     /** Set the number of apps per row when device profile changes. */
@@ -353,7 +361,7 @@
         // Split of private space apps into user-installed and system apps.
         Map<Boolean, List<AppInfo>> split = mPrivateApps.stream()
                 .collect(Collectors.partitioningBy(mPrivateProviderManager
-                                .splitIntoUserInstalledAndSystemApps()));
+                                .splitIntoUserInstalledAndSystemApps(mActivityContext)));
 
         // TODO(b/329688630): switch to the pulled LayoutStaticSnapshot atom
         mActivityContext
@@ -383,6 +391,7 @@
     private int addAppsWithSections(List<AppInfo> appList, int startPosition) {
         String lastSectionName = null;
         boolean hasPrivateApps = false;
+        int position = startPosition;
         if (mPrivateProviderManager != null) {
             hasPrivateApps = appList.stream().
                     allMatch(mPrivateProviderManager.getItemInfoMatcher());
@@ -403,11 +412,12 @@
             // Create a new section if the section names do not match
             if (!sectionName.equals(lastSectionName)) {
                 lastSectionName = sectionName;
-                mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, startPosition));
+                mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
+                        mPrivateProfileAppScrollerBadge : sectionName, position));
             }
-            startPosition++;
+            position++;
         }
-        return startPosition;
+        return position;
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 3ba1eed..16630967 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.allapps;
 
+import static android.view.View.GONE;
+
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
@@ -263,15 +265,25 @@
                 icon.applyFromApplicationInfo(adapterItem.itemInfo);
                 icon.setOnFocusChangeListener(mIconFocusListener);
                 PrivateProfileManager privateProfileManager = mApps.getPrivateProfileManager();
-                // Set the alpha of the private space icon to 0 upon expanding the header so the
-                // alpha can animate -> 1.
-                if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
-                    icon.setAlpha(privateProfileManager != null
-                            && privateProfileManager.isPrivateSpaceItem(adapterItem)
-                            && privateProfileManager.getAnimationScrolling()
-                            && privateProfileManager.getAnimate()
-                            && privateProfileManager.getCurrentState() == STATE_ENABLED
-                            ? 0 : 1);
+                if (privateProfileManager != null) {
+                    // Set the alpha of the private space icon to 0 upon expanding the header so the
+                    // alpha can animate -> 1.
+                    boolean isPrivateSpaceItem =
+                            privateProfileManager.isPrivateSpaceItem(adapterItem);
+                    if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
+                        icon.setAlpha(isPrivateSpaceItem
+                                && (privateProfileManager.getAnimationScrolling() ||
+                                    privateProfileManager.getAnimate())
+                                && privateProfileManager.getCurrentState() == STATE_ENABLED
+                                ? 0 : 1);
+                    }
+                    // Views can still be bounded before the app list is updated hence showing icons
+                    // after collapsing.
+                    if (privateProfileManager.getCurrentState() == STATE_DISABLED
+                            && isPrivateSpaceItem) {
+                        adapterItem.decorationInfo = null;
+                        icon.setVisibility(GONE);
+                    }
                 }
                 break;
             }
@@ -298,7 +310,8 @@
                 break;
             case VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER:
                 adapterItem = mApps.getAdapterItems().get(position);
-                adapterItem.decorationInfo = new SectionDecorationInfo(mActivityContext,
+                adapterItem.decorationInfo = mApps.getPrivateProfileManager().getCurrentState()
+                        == STATE_DISABLED ? null : new SectionDecorationInfo(mActivityContext,
                         ROUND_NOTHING, true /* decorateTogether */);
                 break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
diff --git a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
index 18175b6..339e443 100644
--- a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
@@ -43,6 +43,9 @@
         for (int i = 0; i < parent.getChildCount(); i++) {
             View view = parent.getChildAt(i);
             int position = parent.getChildAdapterPosition(view);
+            if (position < 0 || position >= mAppsList.getAdapterItems().size()) {
+                continue;
+            }
             BaseAllAppsAdapter.AdapterItem adapterItem = mAppsList.getAdapterItems().get(position);
             SectionDecorationInfo info = adapterItem.decorationInfo;
             if (info == null) {
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index fc186e8..53f9cfc 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -20,15 +20,19 @@
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
@@ -79,9 +83,7 @@
 import com.android.launcher3.views.RecyclerViewFastScroller;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.function.Predicate;
 
 /**
@@ -90,7 +92,15 @@
  */
 public class PrivateProfileManager extends UserProfileManager {
     private static final int EXPAND_COLLAPSE_DURATION = 800;
-    private static final int SETTINGS_OPACITY_DURATION = 160;
+    private static final int SETTINGS_OPACITY_DURATION = 400;
+    private static final int TEXT_UNLOCK_OPACITY_DURATION = 300;
+    private static final int TEXT_LOCK_OPACITY_DURATION = 50;
+    private static final int APP_OPACITY_DURATION = 400;
+    private static final int APP_OPACITY_DELAY = 400;
+    private static final int SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY = 400;
+    private static final int SETTINGS_OPACITY_DELAY = 400;
+    private static final int LOCK_TEXT_OPACITY_DELAY = 500;
+    private static final int NO_DELAY = 0;
     private final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
     private final int mPsHeaderHeight;
@@ -104,7 +114,6 @@
             }
         }
     };
-    private Set<String> mPreInstalledSystemPackages = new HashSet<>();
     private Intent mAppInstallerIntent = new Intent();
     private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
     private boolean mPrivateSpaceSettingsAvailable;
@@ -114,6 +123,8 @@
     private Runnable mOnPSHeaderAdded;
     @Nullable
     private RelativeLayout mPSHeader;
+    private final String mLockedStateContentDesc;
+    private final String mUnLockedStateContentDesc;
 
     public PrivateProfileManager(UserManager userManager,
             ActivityAllAppsContainerView<?> allApps,
@@ -127,6 +138,10 @@
         UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext));
         mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize(
                 R.dimen.ps_header_height);
+        mLockedStateContentDesc = mAllApps.getContext()
+                .getString(R.string.ps_container_lock_button_content_description);
+        mUnLockedStateContentDesc = mAllApps.getContext()
+                .getString(R.string.ps_container_unlock_button_content_description);
     }
 
     /** Adds Private Space Header to the layout. */
@@ -198,6 +213,7 @@
      * when animation is not running.
      */
     public void reset() {
+        getMainRecyclerView().setChildAttachedConsumer(null);
         int previousState = getCurrentState();
         boolean isEnabled = !mAllApps.getAppsStore()
                 .hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
@@ -214,11 +230,27 @@
         resetPrivateSpaceDecorator(updatedState);
     }
 
-    /** Opens the Private Space Settings Page. */
-    public void openPrivateSpaceSettings() {
+    /**
+     * Opens the Private Space Settings Page.
+     *
+     * @param view the view that was clicked to open the settings page and which will be the same
+     *             view to animate back. Otherwise if there is no view, simply start the activity.
+     */
+    public void openPrivateSpaceSettings(View view) {
         if (mPrivateSpaceSettingsAvailable) {
-            mAllApps.getContext().startActivity(
-                    ApiWrapper.INSTANCE.get(mAllApps.getContext()).getPrivateSpaceSettingsIntent());
+            Context context = mAllApps.getContext();
+            Intent intent = ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
+            if (view == null) {
+                context.startActivity(intent);
+                return;
+            }
+            ActivityContext activityContext = ActivityContext.lookupContext(context);
+            AppInfo itemInfo = new AppInfo();
+            itemInfo.id = CONTAINER_PRIVATESPACE;
+            itemInfo.componentName = intent.getComponent();
+            itemInfo.container = CONTAINER_PRIVATESPACE;
+            view.setTag(itemInfo);
+            activityContext.startActivitySafely(view, intent, itemInfo);
         }
     }
 
@@ -246,8 +278,6 @@
         ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(appContext);
         UserHandle profileUser = getProfileUser();
         if (profileUser != null) {
-            mPreInstalledSystemPackages = new HashSet<>(
-                    apiWrapper.getPreInstalledSystemPackages(profileUser));
             mAppInstallerIntent = apiWrapper
                     .getAppMarketActivityIntent(BuildConfig.APPLICATION_ID, profileUser);
         }
@@ -331,10 +361,12 @@
      * Splits private apps into user installed and system apps.
      * When the list of system apps is empty, all apps are treated as system.
      */
-    public Predicate<AppInfo> splitIntoUserInstalledAndSystemApps() {
-        return appInfo -> !mPreInstalledSystemPackages.isEmpty()
+    public Predicate<AppInfo> splitIntoUserInstalledAndSystemApps(Context context) {
+        List<String> preInstallApps = UserCache.getInstance(context)
+                .getPreInstallApps(getProfileUser());
+        return appInfo -> !preInstallApps.isEmpty()
                 && (appInfo.componentName == null
-                || !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName())));
+                || !(preInstallApps.contains(appInfo.componentName.getPackageName())));
     }
 
     /** Add Private Space Header view elements based upon {@link UserProfileState} */
@@ -383,11 +415,13 @@
                 lockText.setVisibility(VISIBLE);
                 lockButton.setVisibility(VISIBLE);
                 lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
+                lockButton.setContentDescription(mUnLockedStateContentDesc);
             }
             case STATE_DISABLED -> {
                 lockText.setVisibility(GONE);
                 lockButton.setVisibility(VISIBLE);
                 lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
+                lockButton.setContentDescription(mLockedStateContentDesc);
             }
             default -> lockButton.setVisibility(GONE);
         }
@@ -397,9 +431,14 @@
         if (getCurrentState() == STATE_DISABLED) {
             header.setOnClickListener(view -> lockingAction(/* lock */ false));
             header.setClickable(true);
+            // Add header as accessibility target when disabled.
+            header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+            header.setContentDescription(mLockedStateContentDesc);
         } else {
             header.setOnClickListener(null);
             header.setClickable(false);
+            // Remove header from accessibility target when enabled.
+            header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
         }
     }
 
@@ -417,11 +456,10 @@
         if (getCurrentState() == STATE_ENABLED
                 && isPrivateSpaceSettingsAvailable()) {
             settingsButton.setVisibility(VISIBLE);
-            settingsButton.setAlpha(1f);
             settingsButton.setOnClickListener(
                     view -> {
                         logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
-                        openPrivateSpaceSettings();
+                        openPrivateSpaceSettings(view);
                     });
         } else {
             settingsButton.setVisibility(GONE);
@@ -562,7 +600,9 @@
         List<BaseAllAppsAdapter.AdapterItem> allAppsAdapterItems =
                 mAllApps.getActiveRecyclerView().getApps().getAdapterItems();
         ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
-        alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        alphaAnim.setDuration(APP_OPACITY_DURATION)
+                .setStartDelay(isExpanding ? APP_OPACITY_DELAY : NO_DELAY);
+        alphaAnim.setInterpolator(Interpolators.LINEAR);
         alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
@@ -589,38 +629,54 @@
      * here.
      */
     private void updatePrivateStateAnimator(boolean expand) {
+        if (!Flags.enablePrivateSpace() || !Flags.privateSpaceAnimation()) {
+            return;
+        }
         if (mPSHeader == null) {
             mOnPSHeaderAdded = () -> updatePrivateStateAnimator(expand);
             setAnimationRunning(false);
             return;
         }
         ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
-        ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
         if (settingsAndLockGroup.getLayoutTransition() == null) {
             // Set a new transition if the current ViewGroup does not already contain one as each
             // transition should only happen once when applied.
             enableLayoutTransition(settingsAndLockGroup);
         }
+        settingsAndLockGroup.getLayoutTransition().setStartDelay(
+                LayoutTransition.CHANGING,
+                expand ? SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY : NO_DELAY);
         PropertySetter headerSetter = new AnimatedPropertySetter();
-        ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
-        updateSettingsGearAlpha(settingsButton, expand, headerSetter);
+        headerSetter.add(updateSettingsGearAlpha(expand));
+        headerSetter.add(updateLockTextAlpha(expand));
         AnimatorSet animatorSet = headerSetter.buildAnim();
         animatorSet.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
+                mStatsLogManager.logger().sendToInteractionJankMonitor(
+                        expand
+                                ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN
+                                : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN,
+                        mAllApps.getActiveRecyclerView());
                 // Animate the collapsing of the text at the same time while updating lock button.
-                lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+                mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
                 setAnimationRunning(true);
             }
         });
         animatorSet.addListener(forEndCallback(() -> {
             setAnimationRunning(false);
+            getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
+            mStatsLogManager.logger().sendToInteractionJankMonitor(
+                    expand
+                            ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END
+                            : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END,
+                    mAllApps.getActiveRecyclerView());
             if (!expand) {
                 // Call onAppsUpdated() because it may be canceled when this animation occurs.
                 mAllApps.getPersonalAppList().onAppsUpdated();
                 if (isPrivateSpaceHidden()) {
                     // TODO (b/325455879): Figure out if we can avoid this.
-                    mAllApps.getActiveRecyclerView().getAdapter().notifyDataSetChanged();
+                    getMainRecyclerView().getAdapter().notifyDataSetChanged();
                 }
             }
         }));
@@ -664,6 +720,8 @@
         LayoutTransition settingsAndLockTransition = new LayoutTransition();
         settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
         settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+        settingsAndLockTransition.setInterpolator(LayoutTransition.CHANGING,
+                Interpolators.STANDARD);
         settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
             @Override
             public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
@@ -680,11 +738,44 @@
     }
 
     /** Change the settings gear alpha when expanded or collapsed. */
-    private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
-            PropertySetter setter) {
-        float toAlpha = expand ? 1 : 0;
-        setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
-                .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+    private ValueAnimator updateSettingsGearAlpha(boolean expand) {
+        if (mPSHeader == null) {
+            return new ValueAnimator();
+        }
+        float from = expand ? 0 : 1;
+        float to = expand ? 1 : 0;
+        ValueAnimator settingsAlphaAnim = ObjectAnimator.ofFloat(from, to);
+        settingsAlphaAnim.setDuration(SETTINGS_OPACITY_DURATION);
+        settingsAlphaAnim.setStartDelay(expand ? SETTINGS_OPACITY_DELAY : NO_DELAY);
+        settingsAlphaAnim.setInterpolator(Interpolators.LINEAR);
+        settingsAlphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                mPSHeader.findViewById(R.id.ps_settings_button)
+                        .setAlpha((float) valueAnimator.getAnimatedValue());
+            }
+        });
+        return settingsAlphaAnim;
+    }
+
+    private ValueAnimator updateLockTextAlpha(boolean expand) {
+        if (mPSHeader == null) {
+            return new ValueAnimator();
+        }
+        float from = expand ? 0 : 1;
+        float to = expand ? 1 : 0;
+        ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+        alphaAnim.setDuration(expand ? TEXT_UNLOCK_OPACITY_DURATION : TEXT_LOCK_OPACITY_DURATION);
+        alphaAnim.setStartDelay(expand ? LOCK_TEXT_OPACITY_DELAY : NO_DELAY);
+        alphaAnim.setInterpolator(Interpolators.LINEAR);
+        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                mPSHeader.findViewById(R.id.lock_text).setAlpha(
+                        (float) valueAnimator.getAnimatedValue());
+            }
+        });
+        return alphaAnim;
     }
 
     void expandPrivateSpace() {
@@ -724,6 +815,10 @@
         allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
     }
 
+    AllAppsRecyclerView getMainRecyclerView() {
+        return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
+    }
+
     boolean getAnimate() {
         return mAnimate;
     }
@@ -737,6 +832,7 @@
     }
 
     boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
-        return item.decorationInfo != null;
+        return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
+                || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
     }
 }
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 6a1f37a..3351ee3 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -52,11 +52,11 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface UserProfileState { }
 
+    protected final StatsLogManager mStatsLogManager;
     @UserProfileState
     private int mCurrentState;
 
     private final UserManager mUserManager;
-    private final StatsLogManager mStatsLogManager;
     private final UserCache mUserCache;
 
     protected UserProfileManager(UserManager userManager,
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index eb7d429..6049574 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,14 +15,10 @@
  */
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
-
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.View;
 import android.view.WindowInsets;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -35,7 +31,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 /**
@@ -53,12 +48,11 @@
     private final Rect mImeInsets = new Rect();
     private int mFlags;
     private final ActivityContext mActivityContext;
+    private final Context mContext;
 
     // Threshold when user scrolls up/down to determine when should button extend/collapse
     private final int mScrollThreshold;
-    private ImageView mIcon;
     private TextView mTextView;
-    private final StatsLogManager mStatsLogManager;
 
 
     public WorkModeSwitch(@NonNull Context context) {
@@ -71,16 +65,15 @@
 
     public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mContext = context;
         mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
         mActivityContext = ActivityContext.lookupContext(getContext());
-        mStatsLogManager = mActivityContext.getStatsLogManager();
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mIcon = findViewById(R.id.work_icon);
         mTextView = findViewById(R.id.pause_text);
         setSelected(true);
         KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
@@ -114,13 +107,8 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        View parent = (View) getParent();
         boolean isRtl = Utilities.isRtl(getResources());
-        Rect allAppsPadding = mActivityContext.getDeviceProfile().allAppsPadding;
-        int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight()
-                - (allAppsPadding.left + allAppsPadding.right);
-        int tabWidth = getTabWidth(getContext(), size);
-        int shift = (size - tabWidth) / 2 + (isRtl ? allAppsPadding.left : allAppsPadding.right);
+        int shift = mActivityContext.getDeviceProfile().getAllAppsIconStartMargin(mContext);
         setTranslationX(isRtl ? shift : -shift);
     }
 
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index ab47097..8121d2a 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -22,13 +22,9 @@
 import android.os.Handler;
 
 import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.search.SearchAlgorithm;
 import com.android.launcher3.search.SearchCallback;
@@ -67,16 +63,12 @@
 
     @Override
     public void doSearch(String query, SearchCallback<AdapterItem> callback) {
-        mAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(@NonNull final LauncherAppState app,
-                    @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-                ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query);
-                if (mAddNoResultsMessage && result.isEmpty()) {
-                    result.add(getEmptyMessageAdapterItem(query));
-                }
-                mResultHandler.post(() -> callback.onSearchResult(query, result));
+        mAppState.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->  {
+            ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query);
+            if (mAddNoResultsMessage && result.isEmpty()) {
+                result.add(getEmptyMessageAdapterItem(query));
             }
+            mResultHandler.post(() -> callback.onSearchResult(query, result));
         });
     }
 
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 1f73241..32445ec 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -30,6 +30,8 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Reorderable;
@@ -85,6 +87,11 @@
                 : activity.getLayoutInflater();
         AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false);
 
+        if (Flags.enableFocusOutline() && activity instanceof Launcher) {
+            icon.setOnFocusChangeListener(((Launcher) activity).getFocusHandler());
+            icon.setDefaultFocusHighlightEnabled(false);
+        }
+
         // Sort contents, so that left-hand app comes first
         appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank));
 
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 830e552..60c413e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.config;
 
-import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
 import static com.android.launcher3.config.FeatureFlags.BooleanFlag.DISABLED;
 import static com.android.launcher3.config.FeatureFlags.BooleanFlag.ENABLED;
 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
@@ -80,13 +79,6 @@
     public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
             "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
             "Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
-
-    public static final BooleanFlag MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE = getDebugFlag(
-            251502424, "ENABLE_BOOT_AWARE_STARTUP_DATA", DISABLED,
-            "Marks LauncherPref data as (and allows it to) available while the device is"
-                    + " locked. Enabling this causes a 1-time movement of certain SharedPreferences"
-                    + " data. Improves startup latency.");
-
     public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
             "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
 
@@ -142,17 +134,6 @@
             "MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
                     + "for home screen");
 
-    public static final BooleanFlag SMARTSPACE_AS_A_WIDGET = getDebugFlag(299181941,
-            "SMARTSPACE_AS_A_WIDGET", DISABLED, "Enable SmartSpace as a widget");
-
-    public static boolean shouldShowFirstPageWidget() {
-        return SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN;
-    }
-
-    public static final BooleanFlag ENABLE_SMARTSPACE_REMOVAL = getDebugFlag(290799975,
-            "ENABLE_SMARTSPACE_REMOVAL", DISABLED, "Enable SmartSpace removal for "
-            + "home screen");
-
     // TODO(Block 11): Clean up flags
     public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
             "FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 05fdcef..ec0a222 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -162,7 +162,7 @@
             finish();
             return;
         }
-        ApplicationInfo info = new PackageManagerHelper(this)
+        ApplicationInfo info = PackageManagerHelper.INSTANCE.get(this)
                 .getApplicationInfo(targetApp.packageName, targetApp.user, 0);
         if (info == null) {
             finish();
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 7a2ec97..7ef3209 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.BubbleTextView.TEXT_ALPHA_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-import static com.android.launcher3.graphics.IconShape.getShape;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -45,6 +44,8 @@
 import com.android.launcher3.anim.PropertyResetListener;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.IconShape.ShapeDelegate;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -233,8 +234,9 @@
         }
         play(a, getAnimator(mFolder.mFooter, ALPHA, 0, 1f), footerStartDelay, footerAlphaDuration);
 
+        ShapeDelegate shapeDelegate = IconShape.INSTANCE.get(mContext).getShape();
         // Create reveal animator for the folder background
-        play(a, getShape().createRevealAnimator(
+        play(a, shapeDelegate.createRevealAnimator(
                 mFolder, startRect, endRect, finalRadius, !mIsOpening));
 
         // Create reveal animator for the folder content (capture the top 4 icons 2x2)
@@ -246,10 +248,9 @@
         int left = mContent.getPaddingLeft() + page * lp.width;
         Rect contentStart = new Rect(left, 0, left + width, height);
         Rect contentEnd = new Rect(left, 0, left + lp.width, lp.height);
-        play(a, getShape().createRevealAnimator(
+        play(a, shapeDelegate.createRevealAnimator(
                 mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
 
-
         // Fade in the folder name, as the text can overlap the icons when grid size is small.
         mFolder.mFolderName.setAlpha(mIsOpening ? 0f : 1f);
         play(a, getAnimator(mFolder.mFolderName, View.ALPHA, 0, 1),
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 4d88b68..00636a3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -112,7 +112,7 @@
 
     @Thunk BubbleTextView mFolderName;
 
-    PreviewBackground mBackground = new PreviewBackground();
+    PreviewBackground mBackground = new PreviewBackground(getContext());
     private boolean mBackgroundIsVisible = true;
 
     FolderGridOrganizer mPreviewVerifier;
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 5d2bb3a..be5f8f7 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -28,11 +28,12 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.ModelTaskController;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.CollectionInfo;
@@ -191,10 +192,11 @@
         nameInfos.setLabel(labels.length - 1, label, 1.0f);
     }
 
-    private class FolderNameWorker extends BaseModelUpdateTask {
+    private class FolderNameWorker implements ModelUpdateTask {
+
         @Override
-        public void execute(@NonNull final LauncherAppState app,
-                @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+        public void execute(@NonNull ModelTaskController taskController,
+                @NonNull BgDataModel dataModel, @NonNull AllAppsList apps) {
             mCollectionInfos = dataModel.collections.clone();
             mAppInfos = Arrays.asList(apps.copyData());
         }
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index ec03803..df41d47 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -19,7 +19,6 @@
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
-import static com.android.launcher3.graphics.IconShape.getShape;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 
 import android.animation.Animator;
@@ -49,6 +48,8 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.celllayout.DelegatedCellDrawing;
+import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.IconShape.ShapeDelegate;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 
@@ -66,6 +67,7 @@
     @VisibleForTesting protected static final float HOVER_SCALE = 1.1f;
     @VisibleForTesting protected static final int HOVER_ANIMATION_DURATION = 300;
 
+    private final Context mContext;
     private final PorterDuffXfermode mShadowPorterDuffXfermode
             = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
     private RadialGradient mShadowShader = null;
@@ -138,6 +140,10 @@
                 }
             };
 
+    public PreviewBackground(Context context) {
+        mContext = context;
+    }
+
     /**
      * Draws folder background under cell layout
      */
@@ -254,6 +260,10 @@
         drawShadow(canvas);
     }
 
+    private ShapeDelegate getShape() {
+        return IconShape.INSTANCE.get(mContext).getShape();
+    }
+
     public void drawShadow(Canvas canvas) {
         if (!DRAW_SHADOW) {
             return;
diff --git a/src/com/android/launcher3/graphics/IconShape.java b/src/com/android/launcher3/graphics/IconShape.java
index f82b07e..5f8f2dc 100644
--- a/src/com/android/launcher3/graphics/IconShape.java
+++ b/src/com/android/launcher3/graphics/IconShape.java
@@ -22,7 +22,6 @@
 import android.animation.FloatArrayEvaluator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -35,7 +34,6 @@
 import android.graphics.Region.Op;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -45,6 +43,8 @@
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconNormalizer;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.views.ClipPathView;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -57,38 +57,94 @@
 /**
  * Abstract representation of the shape of an icon shape
  */
-public abstract class IconShape {
+public final class IconShape implements SafeCloseable {
 
-    private static IconShape sInstance = new Circle();
-    private static float sNormalizationScale = ICON_VISIBLE_AREA_FACTOR;
+    public static final MainThreadInitializedObject<IconShape> INSTANCE =
+            new MainThreadInitializedObject<>(IconShape::new);
 
-    public static IconShape getShape() {
-        return sInstance;
+
+    private ShapeDelegate mDelegate = new Circle();
+    private float mNormalizationScale = ICON_VISIBLE_AREA_FACTOR;
+
+    private IconShape(Context context) {
+        pickBestShape(context);
     }
 
-    public static float getNormalizationScale() {
-        return sNormalizationScale;
+    public ShapeDelegate getShape() {
+        return mDelegate;
     }
 
-    public boolean enableShapeDetection(){
-        return false;
-    };
+    public float getNormalizationScale() {
+        return mNormalizationScale;
+    }
 
-    public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
-            Paint paint);
+    @Override
+    public void close() { }
 
-    public abstract void addToPath(Path path, float offsetX, float offsetY, float radius);
+    /**
+     * Initializes the shape which is closest to the {@link AdaptiveIconDrawable}
+     */
+    public void pickBestShape(Context context) {
+        // Pick any large size
+        final int size = 200;
 
-    public abstract <T extends View & ClipPathView> Animator createRevealAnimator(T target,
-            Rect startRect, Rect endRect, float endRadius, boolean isReversed);
+        Region full = new Region(0, 0, size, size);
+        Region iconR = new Region();
+        AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+                new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
+        drawable.setBounds(0, 0, size, size);
+        iconR.setPath(drawable.getIconMask(), full);
+
+        Path shapePath = new Path();
+        Region shapeR = new Region();
+
+        // Find the shape with minimum area of divergent region.
+        int minArea = Integer.MAX_VALUE;
+        ShapeDelegate closestShape = null;
+        for (ShapeDelegate shape : getAllShapes(context)) {
+            shapePath.reset();
+            shape.addToPath(shapePath, 0, 0, size / 2f);
+            shapeR.setPath(shapePath, full);
+            shapeR.op(iconR, Op.XOR);
+
+            int area = GraphicsUtils.getArea(shapeR);
+            if (area < minArea) {
+                minArea = area;
+                closestShape = shape;
+            }
+        }
+
+        if (closestShape != null) {
+            mDelegate = closestShape;
+        }
+
+        // Initialize shape properties
+        mNormalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, size, null);
+    }
+
+
+
+    public interface ShapeDelegate {
+
+        default boolean enableShapeDetection() {
+            return false;
+        }
+
+        void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint paint);
+
+        void addToPath(Path path, float offsetX, float offsetY, float radius);
+
+        <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
+                Rect startRect, Rect endRect, float endRadius, boolean isReversed);
+    }
 
     /**
      * Abstract shape where the reveal animation is a derivative of a round rect animation
      */
-    private static abstract class SimpleRectShape extends IconShape {
+    private static abstract class SimpleRectShape implements ShapeDelegate {
 
         @Override
-        public final <T extends View & ClipPathView> Animator createRevealAnimator(T target,
+        public final <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
                 Rect startRect, Rect endRect, float endRadius, boolean isReversed) {
             return new RoundedRectRevealOutlineProvider(
                     getStartRadius(startRect), endRadius, startRect, endRect) {
@@ -105,7 +161,7 @@
     /**
      * Abstract shape which draws using {@link Path}
      */
-    private static abstract class PathShape extends IconShape {
+    private static abstract class PathShape implements ShapeDelegate {
 
         private final Path mTmpPath = new Path();
 
@@ -121,7 +177,7 @@
                 Rect startRect, Rect endRect, float endRadius, Path outPath);
 
         @Override
-        public final <T extends View & ClipPathView> Animator createRevealAnimator(T target,
+        public final <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
                 Rect startRect, Rect endRect, float endRadius, boolean isReversed) {
             Path path = new Path();
             AnimatorUpdateListener listener =
@@ -203,7 +259,7 @@
         }
     }
 
-    public static class RoundedSquare extends SimpleRectShape {
+    private static class RoundedSquare extends SimpleRectShape {
 
         /**
          * Ratio of corner radius to half size.
@@ -237,7 +293,7 @@
         }
     }
 
-    public static class TearDrop extends PathShape {
+    private static class TearDrop extends PathShape {
 
         /**
          * Radio of short radius to large radius, based on the shape options defined in the config.
@@ -289,7 +345,7 @@
         }
     }
 
-    public static class Squircle extends PathShape {
+    private static class Squircle extends PathShape {
 
         /**
          * Radio of radius to circle radius, based on the shape options defined in the config.
@@ -375,14 +431,7 @@
         }
     }
 
-    /**
-     * Initializes the shape which is closest to the {@link AdaptiveIconDrawable}
-     */
-    public static void init(Context context) {
-        pickBestShape(context);
-    }
-
-    private static IconShape getShapeDefinition(String type, float radius) {
+    private static ShapeDelegate getShapeDefinition(String type, float radius) {
         switch (type) {
             case "Circle":
                 return new Circle();
@@ -397,8 +446,8 @@
         }
     }
 
-    private static List<IconShape> getAllShapes(Context context) {
-        ArrayList<IconShape> result = new ArrayList<>();
+    private static List<ShapeDelegate> getAllShapes(Context context) {
+        ArrayList<ShapeDelegate> result = new ArrayList<>();
         try (XmlResourceParser parser = context.getResources().getXml(R.xml.folder_shapes)) {
 
             // Find the root tag
@@ -416,7 +465,7 @@
                 if (type == XmlPullParser.START_TAG) {
                     AttributeSet attrs = Xml.asAttributeSet(parser);
                     TypedArray a = context.obtainStyledAttributes(attrs, radiusAttr);
-                    IconShape shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
+                    ShapeDelegate shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
                     a.recycle();
 
                     result.add(shape);
@@ -428,42 +477,4 @@
         return result;
     }
 
-    @TargetApi(Build.VERSION_CODES.O)
-    protected static void pickBestShape(Context context) {
-        // Pick any large size
-        final int size = 200;
-
-        Region full = new Region(0, 0, size, size);
-        Region iconR = new Region();
-        AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
-                new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
-        drawable.setBounds(0, 0, size, size);
-        iconR.setPath(drawable.getIconMask(), full);
-
-        Path shapePath = new Path();
-        Region shapeR = new Region();
-
-        // Find the shape with minimum area of divergent region.
-        int minArea = Integer.MAX_VALUE;
-        IconShape closestShape = null;
-        for (IconShape shape : getAllShapes(context)) {
-            shapePath.reset();
-            shape.addToPath(shapePath, 0, 0, size / 2f);
-            shapeR.setPath(shapePath, full);
-            shapeR.op(iconR, Op.XOR);
-
-            int area = GraphicsUtils.getArea(shapeR);
-            if (area < minArea) {
-                minArea = area;
-                closestShape = shape;
-            }
-        }
-
-        if (closestShape != null) {
-            sInstance = closestShape;
-        }
-
-        // Initialize shape properties
-        sNormalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, size, null);
-    }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 0e4b48e..ae8f1d5 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -24,7 +24,7 @@
 import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE;
 import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
 import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
 
@@ -66,7 +66,6 @@
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -77,7 +76,6 @@
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.WidgetItem;
@@ -88,14 +86,11 @@
 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.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.launcher3.views.ActivityContext;
@@ -104,7 +99,6 @@
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 import com.android.launcher3.widget.LocalColorExtractor;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.ArrayList;
@@ -112,7 +106,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
  * Utility class for generating the preview of Launcher for a given InvariantDeviceProfile.
@@ -131,47 +124,12 @@
      */
     public static class PreviewContext extends SandboxContext {
 
-        private final InvariantDeviceProfile mIdp;
-        private final ConcurrentLinkedQueue<LauncherIconsForPreview> mIconPool =
-                new ConcurrentLinkedQueue<>();
-
         public PreviewContext(Context base, InvariantDeviceProfile idp) {
-            super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
-                    LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
-                    CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
-                    WindowManagerProxy.INSTANCE, DisplayController.INSTANCE);
-            mIdp = idp;
-            mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
-            mObjectMap.put(LauncherAppState.INSTANCE,
+            super(base);
+            putObject(InvariantDeviceProfile.INSTANCE, idp);
+            putObject(LauncherAppState.INSTANCE,
                     new LauncherAppState(this, null /* iconCacheFileName */));
         }
-
-        /**
-         * Creates a new LauncherIcons for the preview, skipping the global pool
-         */
-        public LauncherIcons newLauncherIcons(Context context) {
-            LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll();
-            if (launcherIconsForPreview != null) {
-                return launcherIconsForPreview;
-            }
-            return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize,
-                    -1 /* poolId */);
-        }
-
-        private final class LauncherIconsForPreview extends LauncherIcons {
-
-            private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize,
-                    int poolId) {
-                super(context, fillResIconDpi, iconBitmapSize, poolId);
-            }
-
-            @Override
-            public void recycle() {
-                // Clear any temporary state variables
-                clear();
-                mIconPool.offer(this);
-            }
-        }
     }
 
     private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
@@ -229,10 +187,11 @@
                 launcherWidgetSpanInfo;
 
         CellLayout firstScreen = mRootView.findViewById(R.id.workspace);
-        firstScreen.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingPx.left,
+        firstScreen.setPadding(
+                mDp.workspacePadding.left + mDp.cellLayoutPaddingPx.left,
                 mDp.workspacePadding.top + mDp.cellLayoutPaddingPx.top,
-                (mDp.isTwoPanels ? mDp.cellLayoutBorderSpacePx.x / 2
-                        : mDp.workspacePadding.right) + mDp.cellLayoutPaddingPx.right,
+                mDp.isTwoPanels ? (mDp.cellLayoutBorderSpacePx.x / 2)
+                        : (mDp.workspacePadding.right + mDp.cellLayoutPaddingPx.right),
                 mDp.workspacePadding.bottom + mDp.cellLayoutPaddingPx.bottom
         );
         mWorkspaceScreens.put(FIRST_SCREEN_ID, firstScreen);
@@ -240,7 +199,7 @@
         if (mDp.isTwoPanels) {
             CellLayout rightPanel = mRootView.findViewById(R.id.workspace_right);
             rightPanel.setPadding(
-                    mDp.cellLayoutBorderSpacePx.x / 2  + mDp.cellLayoutPaddingPx.left,
+                    mDp.cellLayoutBorderSpacePx.x / 2,
                     mDp.workspacePadding.top + mDp.cellLayoutPaddingPx.top,
                     mDp.workspacePadding.right + mDp.cellLayoutPaddingPx.right,
                     mDp.workspacePadding.bottom + mDp.cellLayoutPaddingPx.bottom
@@ -419,7 +378,7 @@
 
     private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
         WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
-                info.providerName, info.user);
+                info.providerName, info.user, mContext);
         if (widgetItem == null) {
             return;
         }
@@ -546,7 +505,7 @@
 
         // Add first page QSB
         if (FeatureFlags.QSB_ON_FIRST_SCREEN && dataModel.isFirstPagePinnedItemEnabled
-                && !shouldShowFirstPageWidget()) {
+                && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
             View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
             CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index af704a8..329f717 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -572,7 +572,7 @@
         try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
             final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
                     mContext.getDrawable(widgetSection.mSectionDrawable),
-                    new BaseIconFactory.IconOptions().setShrinkNonAdaptiveIcons(false));
+                    new BaseIconFactory.IconOptions());
             mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap);
             infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user);
         } catch (Exception e) {
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 513377a..e90a1e0 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -25,78 +25,53 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.LauncherPreviewRenderer;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.UserIconInfo;
 
+import java.util.concurrent.ConcurrentLinkedQueue;
+
 /**
  * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
  * that are threadsafe.
  */
 public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
 
-    private static final Object sPoolSync = new Object();
-    private static LauncherIcons sPool;
-    private static int sPoolId = 0;
+    private static final MainThreadInitializedObject<Pool> POOL =
+            new MainThreadInitializedObject<>(Pool::new);
 
     /**
      * Return a new Message instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      */
     public static LauncherIcons obtain(Context context) {
-        if (context instanceof LauncherPreviewRenderer.PreviewContext) {
-            return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context);
-        }
-
-        int poolId;
-        synchronized (sPoolSync) {
-            if (sPool != null) {
-                LauncherIcons m = sPool;
-                sPool = m.next;
-                m.next = null;
-                return m;
-            }
-            poolId = sPoolId;
-        }
-
-        InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
-        return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+        return POOL.get(context).obtain();
     }
 
-    public static void clearPool() {
-        synchronized (sPoolSync) {
-            sPool = null;
-            sPoolId++;
-        }
+    public static void clearPool(Context context) {
+        POOL.get(context).close();
     }
 
-    private final int mPoolId;
-
-    private LauncherIcons next;
+    private final ConcurrentLinkedQueue<LauncherIcons> mPool;
 
     private MonochromeIconFactory mMonochromeIconFactory;
 
-    protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
-        super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection());
+    protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize,
+            ConcurrentLinkedQueue<LauncherIcons> pool) {
+        super(context, fillResIconDpi, iconBitmapSize,
+                IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
         mMonoIconEnabled = Themes.isThemedIconEnabled(context);
-        mPoolId = poolId;
+        mPool = pool;
     }
 
     /**
      * Recycles a LauncherIcons that may be in-use.
      */
     public void recycle() {
-        synchronized (sPoolSync) {
-            if (sPoolId != mPoolId) {
-                return;
-            }
-            // Clear any temporary state variables
-            clear();
-
-            next = sPool;
-            sPool = this;
-        }
+        clear();
+        mPool.add(this);
     }
 
     @Override
@@ -121,4 +96,33 @@
     public void close() {
         recycle();
     }
+
+    private static class Pool implements SafeCloseable {
+
+        private final Context mContext;
+
+        @NonNull
+        private ConcurrentLinkedQueue<LauncherIcons> mPool = new ConcurrentLinkedQueue<>();
+
+        private Pool(Context context) {
+            mContext = context;
+        }
+
+        public LauncherIcons obtain() {
+            ConcurrentLinkedQueue<LauncherIcons> pool = mPool;
+            LauncherIcons m = pool.poll();
+
+            if (m == null) {
+                InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext);
+                return new LauncherIcons(mContext, idp.fillResIconDpi, idp.iconBitmapSize, pool);
+            } else {
+                return m;
+            }
+        }
+
+        @Override
+        public void close() {
+            mPool = new ConcurrentLinkedQueue<>();
+        }
+    }
 }
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 456cde8..480e8f3 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -246,7 +246,8 @@
 
     protected void setCurrentItem(T item) {
         mCurrentItem = item;
-        mShift = 0;
+        // Set it to end value directly to skip the animation for outline
+        mShift = Flags.enableFocusOutline() ? 1 : 0;
         mTargetItem = null;
     }
 
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
index 4653bf1..21d157a 100644
--- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.view.View;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.PagedView;
 
 /**
@@ -35,6 +36,28 @@
     }
 
     @Override
+    protected boolean shouldDraw(View item) {
+        if (Flags.enableFocusOutline()) {
+            // Not draw outline in page transition because the outline just remains fully
+            // persistent during the transition and does not look smooth
+            return super.shouldDraw(item) && !isInPageTransition(item);
+        } else {
+            return super.shouldDraw(item);
+        }
+    }
+
+    private boolean isInPageTransition(View view) {
+        if (view == null || !(view.getParent() instanceof View)) {
+            return false;
+        }
+        boolean isInTransition = false;
+        if (view instanceof PagedView) {
+            isInTransition = ((PagedView<?>) view).isPageInTransition();
+        }
+        return isInTransition || isInPageTransition((View) view.getParent());
+    }
+
+    @Override
     public void viewToRect(View v, Rect outRect) {
         // Using FocusedRect here allows views to provide their custom rect for drawing outline,
         // e.g. making the Rect bigger than the content to leave some padding between view and
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 441bbb5..25eeacb 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -769,7 +769,19 @@
         LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT(1672),
 
         @UiEvent(doc = "Number of preinstalled Private profile apps, shown under separator line")
-        LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673)
+        LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673),
+
+        @UiEvent(doc = "Private space lock animation started")
+        LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN(1725),
+
+        @UiEvent(doc = "Private space lock animation finished")
+        LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END(1726),
+
+        @UiEvent(doc = "Private space unlock animation started")
+        LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN(1727),
+
+        @UiEvent(doc = "Private space unlock animation finished")
+        LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END(1728)
 
         // ADD MORE
         ;
@@ -1205,7 +1217,7 @@
      * Creates a new instance of {@link StatsLogManager} based on provided context.
      */
     public static StatsLogManager newInstance(Context context) {
-        return Overrides.getObject(StatsLogManager.class,
-                context.getApplicationContext(), R.string.stats_log_manager_class);
+        return Overrides.getObject(
+                StatsLogManager.class, context, R.string.stats_log_manager_class);
     }
 }
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ce563b7..427fb97 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.model;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
@@ -25,9 +26,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel.CallbackTask;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
@@ -49,7 +51,7 @@
 /**
  * Task to add auto-created workspace items.
  */
-public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
+public class AddWorkspaceItemsTask implements ModelUpdateTask {
 
     private static final String LOG = "AddWorkspaceItemsTask";
 
@@ -76,15 +78,17 @@
         mItemSpaceFinder = itemSpaceFinder;
     }
 
+
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
         if (mItemList.isEmpty()) {
             return;
         }
 
         final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
         final IntArray addedWorkspaceScreensFinal = new IntArray();
+        final Context context = taskController.getApp().getContext();
 
         synchronized (dataModel) {
             IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
@@ -99,7 +103,7 @@
                     }
 
                     // b/139663018 Short-circuit this logic if the icon is a system app
-                    if (PackageManagerHelper.isSystemApp(app.getContext(),
+                    if (PackageManagerHelper.isSystemApp(context,
                             Objects.requireNonNull(item.getIntent()))) {
                         continue;
                     }
@@ -112,7 +116,7 @@
 
                 if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                     if (item instanceof WorkspaceItemFactory) {
-                        item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+                        item = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
                     }
                 }
                 if (item != null) {
@@ -121,13 +125,13 @@
             }
 
             InstallSessionHelper packageInstaller =
-                    InstallSessionHelper.INSTANCE.get(app.getContext());
-            LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
+                    InstallSessionHelper.INSTANCE.get(context);
+            LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
 
             for (ItemInfo item : filteredItems) {
                 // Find appropriate space for the item.
-                int[] coords = mItemSpaceFinder.findSpaceForItem(app, dataModel, workspaceScreens,
-                        addedWorkspaceScreensFinal, item.spanX, item.spanY);
+                int[] coords = mItemSpaceFinder.findSpaceForItem(taskController.getApp(), dataModel,
+                        workspaceScreens, addedWorkspaceScreensFinal, item.spanX, item.spanY);
                 int screenId = coords[0];
 
                 ItemInfo itemInfo;
@@ -135,7 +139,7 @@
                         || item instanceof LauncherAppWidgetInfo) {
                     itemInfo = item;
                 } else if (item instanceof WorkspaceItemFactory) {
-                    itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+                    itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
                 } else {
                     throw new RuntimeException("Unexpected info type");
                 }
@@ -174,8 +178,8 @@
                     if (hasActivity) {
                         // App was installed while launcher was in the background,
                         // or app was already installed for another user.
-                        itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
-                                .makeWorkspaceItem(app.getContext());
+                        itemInfo = new AppInfo(context, activities.get(0), item.user)
+                                .makeWorkspaceItem(context);
 
                         if (shortcutExists(dataModel, itemInfo.getIntent(), itemInfo.user)) {
                             // We need this additional check here since we treat all auto added
@@ -185,16 +189,17 @@
                             continue;
                         }
 
+                        IconCache cache = taskController.getApp().getIconCache();
                         WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
                         wii.title = "";
-                        wii.bitmap = app.getIconCache().getDefaultIcon(item.user);
-                        app.getIconCache().getTitleAndIcon(wii,
+                        wii.bitmap = cache.getDefaultIcon(item.user);
+                        cache.getTitleAndIcon(wii,
                                 ((WorkspaceItemInfo) itemInfo).usingLowResIcon());
                     }
                 }
 
                 // Add the shortcut to the db
-                getModelWriter().addItemToDatabase(itemInfo,
+                taskController.getModelWriter().addItemToDatabase(itemInfo,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
                         coords[1], coords[2]);
 
@@ -207,7 +212,7 @@
         }
 
         if (!addedItemsFinal.isEmpty()) {
-            scheduleCallbackTask(new CallbackTask() {
+            taskController.scheduleCallbackTask(new CallbackTask() {
                 @Override
                 public void execute(@NonNull Callbacks callbacks) {
                     final ArrayList<ItemInfo> addAnimated = new ArrayList<>();
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 8c5ea79..64ebbf3 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -33,14 +32,14 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AppFilter;
-import com.android.launcher3.Flags;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SafeCloseable;
@@ -61,7 +60,7 @@
 
     private static final String TAG = "AllAppsList";
     private static final Consumer<AppInfo> NO_OP_CONSUMER = a -> { };
-
+    private static final boolean DEBUG = true;
 
     public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
 
@@ -170,7 +169,7 @@
     public AppInfo addPromiseApp(
             Context context, PackageInstallInfo installInfo, boolean loadIcon) {
         // only if not yet installed
-        if (new PackageManagerHelper(context)
+        if (PackageManagerHelper.INSTANCE.get(context)
                 .isAppInstalled(installInfo.packageName, installInfo.user)) {
             return null;
         }
@@ -221,6 +220,11 @@
                     updatedAppInfos.add(appInfo);
                 } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED
                         && !appInfo.isAppStartable()) {
+                    if (DEBUG) {
+                        Log.w(TAG, "updatePromiseInstallInfo: removing app due to install"
+                                + " failure and appInfo not startable."
+                                + " package=" + appInfo.getTargetPackage());
+                    }
                     removeApp(i);
                 }
             }
@@ -300,6 +304,9 @@
      */
     public List<LauncherActivityInfo> updatePackage(
             Context context, String packageName, UserHandle user) {
+        final ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(context);
+        final UserCache userCache = UserCache.getInstance(context);
+        final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
         final List<LauncherActivityInfo> matches = context.getSystemService(LauncherApps.class)
                 .getActivityList(packageName, user);
         if (matches.size() > 0) {
@@ -310,7 +317,10 @@
                 if (user.equals(applicationInfo.user)
                         && packageName.equals(applicationInfo.componentName.getPackageName())) {
                     if (!findActivity(matches, applicationInfo.componentName)) {
-                        Log.w(TAG, "Changing shortcut target due to app component name change.");
+                        if (DEBUG) {
+                            Log.w(TAG, "Changing shortcut target due to app component name change."
+                                    + " package=" + packageName);
+                        }
                         removeApp(i);
                     }
                 }
@@ -327,24 +337,18 @@
 
                     mIconCache.getTitleAndIcon(applicationInfo, info, false /* useLowResIcon */);
                     applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
-                    applicationInfo.setProgressLevel(
-                            PackageManagerHelper.getLoadingProgress(info),
-                            PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
                     applicationInfo.intent = launchIntent;
-                    if (Flags.enableSupportForArchiving()) {
-                        // In case an app is archived, the respective item flag corresponding to
-                        // archiving should also be applied during package updates
-                        if (info.getActivityInfo().isArchived) {
-                            applicationInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
-                        } else {
-                            applicationInfo.runtimeStatusFlags &= (~FLAG_ARCHIVED);
-                        }
-                    }
+                    AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info,
+                            userCache.getUserInfo(user), apiWrapper, pmHelper);
                     mDataChanged = true;
                 }
             }
         } else {
             // Remove all data for this package.
+            if (DEBUG) {
+                Log.w(TAG, "updatePromiseInstallInfo: no Activities matched updated package,"
+                        + " removing all apps from package=" + packageName);
+            }
             for (int i = data.size() - 1; i >= 0; i--) {
                 final AppInfo applicationInfo = data.get(i);
                 if (user.equals(applicationInfo.user)
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 41dbe4e..e6ade61 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -17,8 +17,8 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.Flags.enableWorkspaceInflation;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
 import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -327,7 +327,7 @@
             executeCallbacksTask(c -> {
                 c.clearPendingBinds();
                 c.startBinding();
-                if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+                if (enableSmartspaceRemovalToggle()) {
                     c.setIsFirstPagePinnedItemEnabled(
                             mBgDataModel.isFirstPagePinnedItemEnabled);
                 }
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
deleted file mode 100644
index 529c30a..0000000
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.model;
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherModel.CallbackTask;
-import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.celllayout.CellPosMapper;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.BgDataModel.FixedContainerItems;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-/**
- * Extension of {@link ModelUpdateTask} with some utility methods
- */
-public abstract class BaseModelUpdateTask implements ModelUpdateTask {
-
-    private static final boolean DEBUG_TASKS = false;
-    private static final String TAG = "BaseModelUpdateTask";
-
-    // Nullabilities are explicitly omitted here because these are late-init fields,
-    // They will be non-null after init(), which is always the case in enqueueModelUpdateTask().
-    private LauncherAppState mApp;
-    private LauncherModel mModel;
-    private BgDataModel mDataModel;
-    private AllAppsList mAllAppsList;
-    private Executor mUiExecutor;
-
-    public void init(@NonNull final LauncherAppState app, @NonNull final LauncherModel model,
-            @NonNull final BgDataModel dataModel, @NonNull final AllAppsList allAppsList,
-            @NonNull final Executor uiExecutor) {
-        mApp = app;
-        mModel = model;
-        mDataModel = dataModel;
-        mAllAppsList = allAppsList;
-        mUiExecutor = uiExecutor;
-    }
-
-    @Override
-    public final void run() {
-        boolean isModelLoaded = Objects.requireNonNull(mModel).isModelLoaded();
-        if (!isModelLoaded) {
-            if (DEBUG_TASKS) {
-                Log.d(TAG, "Ignoring model task since loader is pending=" + this);
-            }
-            // Loader has not yet run.
-            return;
-        }
-        execute(mApp, mDataModel, mAllAppsList);
-    }
-
-    /**
-     * Execute the actual task. Called on the worker thread.
-     */
-    public abstract void execute(@NonNull LauncherAppState app,
-            @NonNull BgDataModel dataModel, @NonNull AllAppsList apps);
-
-    /**
-     * Schedules a {@param task} to be executed on the current callbacks.
-     */
-    public final void scheduleCallbackTask(@NonNull final CallbackTask task) {
-        for (final Callbacks cb : mModel.getCallbacks()) {
-            mUiExecutor.execute(() -> task.execute(cb));
-        }
-    }
-
-    public ModelWriter getModelWriter() {
-        // Updates from model task, do not deal with icon position in hotseat. Also no need to
-        // verify changes as the ModelTasks always push the changes to callbacks
-        return mModel.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null);
-    }
-
-    public void bindUpdatedWorkspaceItems(@NonNull final List<WorkspaceItemInfo> allUpdates) {
-        // Bind workspace items
-        List<WorkspaceItemInfo> workspaceUpdates = allUpdates.stream()
-                .filter(info -> info.id != ItemInfo.NO_ID)
-                .collect(Collectors.toList());
-        if (!workspaceUpdates.isEmpty()) {
-            scheduleCallbackTask(c -> c.bindWorkspaceItemsChanged(workspaceUpdates));
-        }
-
-        // Bind extra items if any
-        allUpdates.stream()
-                .mapToInt(info -> info.container)
-                .distinct()
-                .mapToObj(mDataModel.extraItems::get)
-                .filter(Objects::nonNull)
-                .forEach(this::bindExtraContainerItems);
-    }
-
-    public void bindExtraContainerItems(@NonNull final FixedContainerItems item) {
-        scheduleCallbackTask(c -> c.bindExtraContainerItems(item));
-    }
-
-    public void bindDeepShortcuts(@NonNull final BgDataModel dataModel) {
-        final HashMap<ComponentKey, Integer> shortcutMapCopy =
-                new HashMap<>(dataModel.deepShortcutMap);
-        scheduleCallbackTask(callbacks -> callbacks.bindDeepShortcutMap(shortcutMapCopy));
-    }
-
-    public void bindUpdatedWidgets(@NonNull final BgDataModel dataModel) {
-        final ArrayList<WidgetsListBaseEntry> widgets =
-                dataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
-        scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
-    }
-
-    public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher,
-            @Nullable final String reason) {
-        getModelWriter().deleteItemsFromDatabase(matcher, reason);
-
-        // Call the components-removed callback
-        scheduleCallbackTask(c -> c.bindWorkspaceComponentsRemoved(matcher));
-    }
-
-    public void bindApplicationsIfNeeded() {
-        if (mAllAppsList.getAndResetChangeFlag()) {
-            AppInfo[] apps = mAllAppsList.copyData();
-            int flags = mAllAppsList.getFlags();
-            Map<PackageUserKey, Integer> packageUserKeytoUidMap = Arrays.stream(apps).collect(
-                    Collectors.toMap(
-                            appInfo -> new PackageUserKey(appInfo.componentName.getPackageName(),
-                                    appInfo.user), appInfo -> appInfo.uid, (a, b) -> a));
-            scheduleCallbackTask(c -> c.bindAllApplications(apps, flags, packageUserKeytoUidMap));
-        }
-    }
-}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index d5de4ce..9a9fa5b 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -19,8 +19,8 @@
 
 import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN;
 import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
 
 import static java.util.stream.Collectors.groupingBy;
@@ -138,7 +138,7 @@
      */
     public int lastLoadId = -1;
     public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN
-            && !ENABLE_SMARTSPACE_REMOVAL.get();
+            && !enableSmartspaceRemovalToggle();
 
     /**
      * Clears all the data
@@ -163,7 +163,7 @@
             }
         }
         if ((FeatureFlags.QSB_ON_FIRST_SCREEN
-                && !shouldShowFirstPageWidget())
+                && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
                 || screenSet.isEmpty()) {
             screenSet.add(Workspace.FIRST_SCREEN_ID);
         }
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 57fefaa..66b4fd9 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -31,7 +31,7 @@
 /**
  * Handles changes due to cache updates.
  */
-public class CacheDataUpdatedTask extends BaseModelUpdateTask {
+public class CacheDataUpdatedTask implements ModelUpdateTask {
 
     public static final int OP_CACHE_UPDATE = 1;
     public static final int OP_SESSION_UPDATE = 2;
@@ -52,9 +52,9 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
-        IconCache iconCache = app.getIconCache();
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
+        IconCache iconCache = taskController.getApp().getIconCache();
         ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
 
         synchronized (dataModel) {
@@ -69,8 +69,8 @@
             });
             apps.updateIconsAndLabels(mPackages, mUser);
         }
-        bindUpdatedWorkspaceItems(updatedShortcuts);
-        bindApplicationsIfNeeded();
+        taskController.bindUpdatedWorkspaceItems(updatedShortcuts);
+        taskController.bindApplicationsIfNeeded();
     }
 
     public boolean isValidShortcut(@NonNull final WorkspaceItemInfo si) {
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 88ca009..132b606 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -16,7 +16,7 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 
 import android.content.ContentValues;
@@ -259,7 +259,7 @@
             }
             case 30: {
                 if (FeatureFlags.QSB_ON_FIRST_SCREEN
-                        && !shouldShowFirstPageWidget()) {
+                        && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
                     // Clean up first row in screen 0 as it might contain junk data.
                     Log.d(TAG, "Cleaning up first row");
                     db.delete(Favorites.TABLE_NAME,
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index f24a7c1..ad32fc2 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -16,10 +16,10 @@
 
 package com.android.launcher3.model;
 
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
 import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
@@ -348,9 +348,9 @@
         final Point trg = new Point(trgX, trgY);
         final Point next = new Point(0, screenId == 0
                 && (FeatureFlags.QSB_ON_FIRST_SCREEN
-                && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(destReader.mContext)
+                && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(destReader.mContext)
                 .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true))
-                && !shouldShowFirstPageWidget())
+                && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
                 ? 1 /* smartspace */ : 0);
         List<DbEntry> existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId);
         if (existedEntries != null) {
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 90aba2a..551c2d8 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -45,7 +45,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -55,6 +54,7 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.PersistedItemArray;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 import java.util.HashSet;
@@ -65,7 +65,7 @@
 /**
  * Class to maintain a queue of pending items to be added to the workspace.
  */
-public class ItemInstallQueue {
+public class ItemInstallQueue implements SafeCloseable {
 
     private static final String LOG = "ItemInstallQueue";
 
@@ -99,6 +99,9 @@
         mContext = context;
     }
 
+    @Override
+    public void close() {}
+
     @WorkerThread
     private void ensureQueueLoaded() {
         Preconditions.assertWorkerThread();
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 2f678a8..84130c7 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -17,7 +17,7 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 
 import android.content.ComponentName;
 import android.content.ContentValues;
@@ -52,10 +52,12 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.UserIconInfo;
 
 import java.net.URISyntaxException;
@@ -72,6 +74,7 @@
 
     private final LauncherAppState mApp;
     private final Context mContext;
+    private final PackageManagerHelper mPmHelper;
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mIDP;
     private final @Nullable LauncherRestoreEventLogger mRestoreEventLogger;
@@ -113,6 +116,7 @@
     public int restoreFlag;
 
     public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState,
+            PackageManagerHelper pmHelper,
             @Nullable LauncherRestoreEventLogger restoreEventLogger) {
         super(cursor);
 
@@ -120,6 +124,7 @@
         allUsers = userManagerState.allUsers;
         mContext = app.getContext();
         mIconCache = app.getIconCache();
+        mPmHelper = pmHelper;
         mIDP = app.getInvariantDeviceProfile();
         mRestoreEventLogger = restoreEventLogger;
 
@@ -366,7 +371,8 @@
         }
 
         if (mActivityInfo != null) {
-            AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo);
+            AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo,
+                    ApiWrapper.INSTANCE.get(mContext), mPmHelper);
         }
 
         // from the db
@@ -548,7 +554,8 @@
         if (!mOccupied.containsKey(item.screenId)) {
             GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
             if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN
-                    && !shouldShowFirstPageWidget() && isFirstPagePinnedItemEnabled)) {
+                    && !SHOULD_SHOW_FIRST_PAGE_WIDGET
+                    && isFirstPagePinnedItemEnabled)) {
                 // Mark the first X columns (X is width of the search container) in the first row as
                 // occupied (if the feature is enabled) in order to account for the search
                 // container.
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index ac4c087..102d28a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -18,11 +18,11 @@
 
 import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
 import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
 import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
@@ -89,6 +89,7 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IOUtils;
 import com.android.launcher3.util.IntArray;
@@ -137,6 +138,7 @@
     private final LauncherApps mLauncherApps;
     private final UserManager mUserManager;
     private final UserCache mUserCache;
+    private final PackageManagerHelper mPmHelper;
 
     private final InstallSessionHelper mSessionHelper;
     private final IconCache mIconCache;
@@ -169,6 +171,7 @@
         mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
         mUserManager = mApp.getContext().getSystemService(UserManager.class);
         mUserCache = UserCache.INSTANCE.get(mApp.getContext());
+        mPmHelper = new PackageManagerHelper(mApp.getContext());
         mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
         mIconCache = mApp.getIconCache();
         mUserManagerState = userManagerState;
@@ -319,13 +322,13 @@
             verifyNotStopped();
             LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
 
-            if (SMARTSPACE_AS_A_WIDGET.get() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
+            if (enableSmartspaceAsAWidget() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
                 mLauncherBinder.bindSmartspaceWidget();
                 // Turn off pref.
                 prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(false));
                 logASplit("bindSmartspaceWidget");
                 verifyNotStopped();
-            } else if (!SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN
+            } else if (!enableSmartspaceAsAWidget() && WIDGET_ON_FIRST_SCREEN
                     && !prefs.get(LauncherPrefs.SHOULD_SHOW_SMARTSPACE)) {
                 // Turn on pref.
                 prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(true));
@@ -396,7 +399,7 @@
             logASplit("workspaceDelegateItems");
         }
         mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
-                && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(
+                && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(
                 mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
     }
 
@@ -406,7 +409,6 @@
             @Nullable LoaderMemoryLogger memoryLogger,
             @Nullable LauncherRestoreEventLogger restoreEventLogger) {
         final Context context = mApp.getContext();
-        final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
         final boolean isSdCardReady = Utilities.isBootCompleted();
         final WidgetInflater widgetInflater = new WidgetInflater(context);
 
@@ -433,7 +435,8 @@
             mShortcutKeyToPinnedShortcuts = new HashMap<>();
             final LoaderCursor c = new LoaderCursor(
                     dbController.query(TABLE_NAME, null, selection, null, null),
-                    mApp, mUserManagerState, mIsRestoreFromBackup ? restoreEventLogger : null);
+                    mApp, mUserManagerState, mPmHelper,
+                    mIsRestoreFromBackup ? restoreEventLogger : null);
             final Bundle extras = c.getExtras();
             mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME);
             try {
@@ -443,10 +446,10 @@
                 List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
 
                 WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger,
-                        mUserManagerState, mLauncherApps, mPendingPackages,
+                        mUserCache, mUserManagerState, mLauncherApps, mPendingPackages,
                         mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel,
                         mWidgetProvidersMap, installingPkgs, isSdCardReady,
-                        widgetInflater, pmHelper, iconRequestInfos, unlockedUsers,
+                        widgetInflater, mPmHelper, iconRequestInfos, unlockedUsers,
                         allDeepShortcuts);
 
                 while (!mStopped && c.moveToNext()) {
@@ -694,7 +697,8 @@
             // Create the ApplicationInfos
             for (int i = 0; i < apps.size(); i++) {
                 LauncherActivityInfo app = apps.get(i);
-                AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user), quietMode);
+                AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user),
+                        ApiWrapper.INSTANCE.get(mApp.getContext()), mPmHelper, quietMode);
                 if (Flags.enableSupportForArchiving() && app.getApplicationInfo().isArchived) {
                     // For archived apps, include progress info in case there is a pending
                     // install session post restart of device.
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 8360b14..2264d35 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -26,6 +26,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.ResourceBasedOverride;
 
 import java.io.FileDescriptor;
@@ -41,15 +42,16 @@
      * Creates and initializes a new instance of the delegate
      */
     public static ModelDelegate newInstance(
-            Context context, LauncherAppState app, AllAppsList appsList, BgDataModel dataModel,
-            boolean isPrimaryInstance) {
+            Context context, LauncherAppState app, PackageManagerHelper pmHelper,
+            AllAppsList appsList, BgDataModel dataModel, boolean isPrimaryInstance) {
         ModelDelegate delegate = Overrides.getObject(
                 ModelDelegate.class, context, R.string.model_delegate_class);
-        delegate.init(app, appsList, dataModel, isPrimaryInstance);
+        delegate.init(app, pmHelper, appsList, dataModel, isPrimaryInstance);
         return delegate;
     }
 
     protected final Context mContext;
+    protected PackageManagerHelper mPmHelper;
     protected LauncherAppState mApp;
     protected AllAppsList mAppsList;
     protected BgDataModel mDataModel;
@@ -62,9 +64,10 @@
     /**
      * Initializes the object with the given params.
      */
-    private void init(LauncherAppState app, AllAppsList appsList,
+    private void init(LauncherAppState app, PackageManagerHelper pmHelper, AllAppsList appsList,
             BgDataModel dataModel, boolean isPrimaryInstance) {
         this.mApp = app;
+        this.mPmHelper = pmHelper;
         this.mAppsList = appsList;
         this.mDataModel = dataModel;
         this.mIsPrimaryInstance = isPrimaryInstance;
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
new file mode 100644
index 0000000..266ed0c
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherModel
+import com.android.launcher3.LauncherModel.CallbackTask
+import com.android.launcher3.celllayout.CellPosMapper
+import com.android.launcher3.model.BgDataModel.FixedContainerItems
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.PackageUserKey
+import java.util.Objects
+import java.util.concurrent.Executor
+import java.util.function.Predicate
+
+/** Class with utility methods and properties for running a LauncherModel Task */
+class ModelTaskController(
+    val app: LauncherAppState,
+    val dataModel: BgDataModel,
+    val allAppsList: AllAppsList,
+    private val model: LauncherModel,
+    private val uiExecutor: Executor
+) {
+
+    /** Schedules a {@param task} to be executed on the current callbacks. */
+    fun scheduleCallbackTask(task: CallbackTask) {
+        for (cb in model.callbacks) {
+            uiExecutor.execute { task.execute(cb) }
+        }
+    }
+
+    /**
+     * Updates from model task, do not deal with icon position in hotseat. Also no need to verify
+     * changes as the ModelTasks always push the changes to callbacks
+     */
+    fun getModelWriter() = model.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null)
+
+    fun bindUpdatedWorkspaceItems(allUpdates: List<WorkspaceItemInfo>) {
+        // Bind workspace items
+        val workspaceUpdates =
+            allUpdates.stream().filter { info -> info.id != ItemInfo.NO_ID }.toList()
+        if (workspaceUpdates.isNotEmpty()) {
+            scheduleCallbackTask { it.bindWorkspaceItemsChanged(workspaceUpdates) }
+        }
+
+        // Bind extra items if any
+        allUpdates
+            .stream()
+            .mapToInt { info: WorkspaceItemInfo -> info.container }
+            .distinct()
+            .mapToObj { dataModel.extraItems.get(it) }
+            .filter { Objects.nonNull(it) }
+            .forEach { bindExtraContainerItems(it) }
+    }
+
+    fun bindExtraContainerItems(item: FixedContainerItems) {
+        scheduleCallbackTask { it.bindExtraContainerItems(item) }
+    }
+
+    fun bindDeepShortcuts(dataModel: BgDataModel) {
+        val shortcutMapCopy = HashMap(dataModel.deepShortcutMap)
+        scheduleCallbackTask { it.bindDeepShortcutMap(shortcutMapCopy) }
+    }
+
+    fun bindUpdatedWidgets(dataModel: BgDataModel) {
+        val widgets = dataModel.widgetsModel.getWidgetsListForPicker(app.context)
+        scheduleCallbackTask { it.bindAllWidgets(widgets) }
+    }
+
+    fun deleteAndBindComponentsRemoved(matcher: Predicate<ItemInfo?>, reason: String?) {
+        getModelWriter().deleteItemsFromDatabase(matcher, reason)
+
+        // Call the components-removed callback
+        scheduleCallbackTask { it.bindWorkspaceComponentsRemoved(matcher) }
+    }
+
+    fun bindApplicationsIfNeeded() {
+        if (allAppsList.getAndResetChangeFlag()) {
+            val apps = allAppsList.copyData()
+            val flags = allAppsList.flags
+            val packageUserKeyToUidMap =
+                apps.associateBy(
+                    keySelector = { PackageUserKey(it.componentName!!.packageName, it.user) },
+                    valueTransform = { it.uid }
+                )
+            scheduleCallbackTask { it.bindAllApplications(apps, flags, packageUserKeyToUidMap) }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
index b9fba9d..f924a9f 100644
--- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
@@ -19,7 +19,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -31,7 +31,7 @@
 /**
  * Handles updates due to incremental download progress updates.
  */
-public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask {
+public class PackageIncrementalDownloadUpdatedTask implements ModelUpdateTask {
 
     @NonNull
     private final UserHandle mUser;
@@ -49,8 +49,8 @@
     }
 
     @Override
-    public void execute(@NonNull LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList appsList) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList appsList) {
         PackageInstallInfo downloadInfo = new PackageInstallInfo(
                 mPackageName,
                 PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING,
@@ -62,11 +62,11 @@
             if (!updatedAppInfos.isEmpty()) {
                 for (AppInfo appInfo : updatedAppInfos) {
                     appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                    scheduleCallbackTask(
+                    taskController.scheduleCallbackTask(
                             c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
                 }
             }
-            bindApplicationsIfNeeded();
+            taskController.bindApplicationsIfNeeded();
         }
 
         final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
@@ -79,6 +79,6 @@
                 }
             });
         }
-        bindUpdatedWorkspaceItems(updatedWorkspaceItems);
+        taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItems);
     }
 }
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 2457a42..d238213 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -15,12 +15,13 @@
  */
 package com.android.launcher3.model;
 
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -33,7 +34,7 @@
 /**
  * Handles changes due to a sessions updates for a currently installing app.
  */
-public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
+public class PackageInstallStateChangedTask implements ModelUpdateTask {
 
     @NonNull
     private final PackageInstallInfo mInstallInfo;
@@ -43,16 +44,17 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
         if (mInstallInfo.state == PackageInstallInfo.STATUS_INSTALLED) {
             try {
                 // For instant apps we do not get package-add. Use setting events to update
                 // any pinned icons.
-                ApplicationInfo ai = app.getContext()
+                Context context = taskController.getApp().getContext();
+                ApplicationInfo ai = context
                         .getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
-                if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) {
-                    app.getModel().newModelCallbacks()
+                if (InstantAppResolver.newInstance(context).isInstantApp(ai)) {
+                    taskController.getApp().getModel().newModelCallbacks()
                             .onPackageAdded(ai.packageName, mInstallInfo.user);
                 }
             } catch (PackageManager.NameNotFoundException e) {
@@ -66,10 +68,11 @@
             List<AppInfo> updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo);
             if (!updatedAppInfos.isEmpty()) {
                 for (AppInfo appInfo : updatedAppInfos) {
-                    scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
+                    taskController.scheduleCallbackTask(
+                            c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
                 }
             }
-            bindApplicationsIfNeeded();
+            taskController.bindApplicationsIfNeeded();
         }
 
         synchronized (dataModel) {
@@ -90,7 +93,8 @@
             }
 
             if (!updates.isEmpty()) {
-                scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
+                taskController.scheduleCallbackTask(
+                        callbacks -> callbacks.bindRestoreItemsChange(updates));
             }
         }
     }
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 1923065..29d2269 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -36,9 +36,9 @@
 
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.FileLog;
@@ -71,11 +71,11 @@
  * or when a user availability changes.
  */
 @SuppressWarnings("NewApi")
-public class PackageUpdatedTask extends BaseModelUpdateTask {
+public class PackageUpdatedTask implements ModelUpdateTask {
 
     // TODO(b/290090023): Set to false after root causing is done.
-    private static final boolean DEBUG = true;
     private static final String TAG = "PackageUpdatedTask";
+    private static final boolean DEBUG = true;
 
     public static final int OP_NONE = 0;
     public static final int OP_ADD = 1;
@@ -102,8 +102,9 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList appsList) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList appsList) {
+        final LauncherAppState app = taskController.getApp();
         final Context context = app.getContext();
         final IconCache iconCache = app.getIconCache();
 
@@ -116,29 +117,39 @@
                 : ItemInfoMatcher.ofPackages(packageSet, mUser);
         final HashSet<ComponentName> removedComponents = new HashSet<>();
         final HashMap<String, List<LauncherActivityInfo>> activitiesLists = new HashMap<>();
-
+        if (DEBUG) {
+            Log.d(TAG, "Package updated: mOp=" + getOpString()
+                    + " packages=" + Arrays.toString(packages));
+        }
         switch (mOp) {
             case OP_ADD: {
                 for (int i = 0; i < N; i++) {
-                    if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
                     iconCache.updateIconsForPkg(packages[i], mUser);
                     if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
+                        if (DEBUG) {
+                            Log.d(TAG, "OP_ADD: PROMISE_APPS_IN_ALL_APPS enabled:"
+                                    + " removing promise icon apps from package=" + packages[i]);
+                        }
                         appsList.removePackage(packages[i], mUser);
                     }
-                    activitiesLists.put(
-                            packages[i], appsList.addPackage(context, packages[i], mUser));
+                    activitiesLists.put(packages[i],
+                            appsList.addPackage(context, packages[i], mUser));
                 }
                 flagOp = FlagOp.NO_OP.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
                 break;
             }
             case OP_UPDATE:
-                try (SafeCloseable t =
-                             appsList.trackRemoves(a -> removedComponents.add(a.componentName))) {
+                try (SafeCloseable t = appsList.trackRemoves(a -> {
+                    Log.d(TAG, "OP_UPDATE - AllAppsList.trackRemoves callback:"
+                            + " removed component=" + a.componentName
+                            + " id=" + a.id
+                            + " Look for earlier AllAppsList logs to find more information.");
+                    removedComponents.add(a.componentName);
+                })) {
                     for (int i = 0; i < N; i++) {
-                        if (DEBUG) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
                         iconCache.updateIconsForPkg(packages[i], mUser);
-                        activitiesLists.put(
-                                packages[i], appsList.updatePackage(context, packages[i], mUser));
+                        activitiesLists.put(packages[i],
+                                appsList.updatePackage(context, packages[i], mUser));
                     }
                 }
                 // Since package was just updated, the target must be available now.
@@ -146,14 +157,15 @@
                 break;
             case OP_REMOVE: {
                 for (int i = 0; i < N; i++) {
-                    FileLog.d(TAG, "Removing app icon: " + packages[i]);
                     iconCache.removeIconsForPkg(packages[i], mUser);
                 }
                 // Fall through
             }
             case OP_UNAVAILABLE:
                 for (int i = 0; i < N; i++) {
-                    if (DEBUG) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
+                    if (DEBUG) {
+                        Log.d(TAG, getOpString() + ": removing package=" + packages[i]);
+                    }
                     appsList.removePackage(packages[i], mUser);
                 }
                 flagOp = FlagOp.NO_OP.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
@@ -162,7 +174,6 @@
             case OP_UNSUSPEND:
                 flagOp = FlagOp.NO_OP.setFlag(
                         WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED, mOp == OP_SUSPEND);
-                if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N);
                 appsList.updateDisabledFlags(matcher, flagOp);
                 break;
             case OP_USER_AVAILABILITY_CHANGE: {
@@ -192,7 +203,7 @@
                 break;
         }
 
-        bindApplicationsIfNeeded();
+        taskController.bindApplicationsIfNeeded();
 
         final IntSet removedShortcuts = new IntSet();
         // Shortcuts to keep even if the corresponding app was removed
@@ -248,12 +259,21 @@
                                     infoUpdated = true;
                                 } else if (si.hasPromiseIconUi()) {
                                     removedShortcuts.add(si.id);
+                                    if (DEBUG) {
+                                        Log.d(TAG, "Removing restored shortcut promise icon"
+                                                + " that no longer points to valid component."
+                                                + " id=" + si.id
+                                                + ", package=" + si.getTargetPackage());
+                                    }
                                     return;
                                 }
                             } else if (!isTargetValid) {
                                 removedShortcuts.add(si.id);
-                                FileLog.e(TAG, "Restored shortcut no longer valid "
-                                        + si.getIntent());
+                                FileLog.e(TAG, "Removing shortcut that no longer points to"
+                                        + " valid component."
+                                        + " id=" + si.id
+                                        + " package=" + si.getTargetPackage()
+                                        + " status=" + si.status);
                                 return;
                             } else {
                                 si.status = WorkspaceItemInfo.DEFAULT;
@@ -268,6 +288,8 @@
                         if (isNewApkAvailable) {
                             List<LauncherActivityInfo> activities = activitiesLists.get(
                                     packageName);
+                            // TODO: See if we can migrate this to
+                            //  AppInfo#updateRuntimeFlagsForActivityTarget
                             si.setProgressLevel(
                                     activities == null || activities.isEmpty()
                                             ? 100
@@ -286,10 +308,8 @@
                             }
                             if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
                                 if (activities != null && !activities.isEmpty()) {
-                                    si.status = ApiWrapper.INSTANCE.get(context)
-                                            .isNonResizeableActivity(activities.get(0))
-                                            ? si.status | WorkspaceItemInfo.FLAG_NON_RESIZEABLE
-                                            : si.status & ~WorkspaceItemInfo.FLAG_NON_RESIZEABLE;
+                                    si.setNonResizeable(ApiWrapper.INSTANCE.get(context)
+                                            .isNonResizeableActivity(activities.get(0)));
                                 }
                                 iconCache.getTitleAndIcon(si, si.usingLowResIcon());
                                 infoUpdated = true;
@@ -307,7 +327,7 @@
                         updatedWorkspaceItems.add(si);
                     }
                     if (infoUpdated && si.id != ItemInfo.NO_ID) {
-                        getModelWriter().updateItemInDatabase(si);
+                        taskController.getModelWriter().updateItemInDatabase(si);
                     }
                 });
 
@@ -326,20 +346,21 @@
                         widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
 
                         widgets.add(widgetInfo);
-                        getModelWriter().updateItemInDatabase(widgetInfo);
+                        taskController.getModelWriter().updateItemInDatabase(widgetInfo);
                     }
                 }
             }
 
-            bindUpdatedWorkspaceItems(updatedWorkspaceItems);
+            taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItems);
             if (!removedShortcuts.isEmpty()) {
-                deleteAndBindComponentsRemoved(
+                taskController.deleteAndBindComponentsRemoved(
                         ItemInfoMatcher.ofItemIds(removedShortcuts),
-                        "removed because the target component is invalid");
+                        "removing shortcuts with invalid target components."
+                                + " ids=" + removedShortcuts);
             }
 
             if (!widgets.isEmpty()) {
-                scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
+                taskController.scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
             }
         }
 
@@ -347,6 +368,9 @@
         if (mOp == OP_REMOVE) {
             // Mark all packages in the broadcast to be removed
             Collections.addAll(removedPackages, packages);
+            if (DEBUG) {
+                Log.d(TAG, "OP_REMOVE: removing packages=" + Arrays.toString(packages));
+            }
 
             // No need to update the removedComponents as
             // removedPackages is a super-set of removedComponents
@@ -355,6 +379,10 @@
             final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
             for (int i=0; i<N; i++) {
                 if (!launcherApps.isPackageEnabled(packages[i], mUser)) {
+                    if (DEBUG) {
+                        Log.d(TAG, "OP_UPDATE:"
+                                + " package " + packages[i] + " is disabled, removing package.");
+                    }
                     removedPackages.add(packages[i]);
                 }
             }
@@ -365,7 +393,7 @@
                     ItemInfoMatcher.ofPackages(removedPackages, mUser)
                             .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                             .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
-            deleteAndBindComponentsRemoved(removeMatch,
+            taskController.deleteAndBindComponentsRemoved(removeMatch,
                     "removed because the corresponding package or component is removed. "
                             + "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
                                     Collectors.joining(",", "[", "]"))
@@ -384,7 +412,7 @@
             for (int i = 0; i < N; i++) {
                 dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
             }
-            bindUpdatedWidgets(dataModel);
+            taskController.bindUpdatedWidgets(dataModel);
         }
     }
 
@@ -400,7 +428,8 @@
             return false;
         }
         // Try to find the best match activity.
-        Intent intent = new PackageManagerHelper(context).getAppLaunchIntent(packageName, mUser);
+        Intent intent = PackageManagerHelper.INSTANCE.get(context)
+                .getAppLaunchIntent(packageName, mUser);
         if (intent != null) {
             si.intent = intent;
             si.status = WorkspaceItemInfo.DEFAULT;
@@ -408,4 +437,18 @@
         }
         return false;
     }
+
+    private String getOpString() {
+        return switch (mOp) {
+            case OP_NONE -> "NONE";
+            case OP_ADD -> "ADD";
+            case OP_UPDATE -> "UPDATE";
+            case OP_REMOVE -> "REMOVE";
+            case OP_UNAVAILABLE -> "UNAVAILABLE";
+            case OP_SUSPEND -> "SUSPEND";
+            case OP_UNSUSPEND -> "UNSUSPEND";
+            case OP_USER_AVAILABILITY_CHANGE -> "USER_AVAILABILITY_CHANGE";
+            default -> "UNKNOWN";
+        };
+    }
 }
diff --git a/src/com/android/launcher3/model/ReloadStringCacheTask.java b/src/com/android/launcher3/model/ReloadStringCacheTask.java
index 34f7057..3d974d6 100644
--- a/src/com/android/launcher3/model/ReloadStringCacheTask.java
+++ b/src/com/android/launcher3/model/ReloadStringCacheTask.java
@@ -17,13 +17,13 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 
 /**
  * Handles updates due to changes in Device Policy Management resources triggered by
  * {@link android.app.admin.DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED}.
  */
-public class ReloadStringCacheTask extends BaseModelUpdateTask {
+public class ReloadStringCacheTask implements ModelUpdateTask {
 
     @NonNull
     private ModelDelegate mModelDelegate;
@@ -33,12 +33,12 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList appsList) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
         synchronized (dataModel) {
             mModelDelegate.loadStringCache(dataModel.stringCache);
             StringCache cloneSC = dataModel.stringCache.clone();
-            scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
+            taskController.scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
         }
     }
 }
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 8cfa3aa..5293316 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -52,7 +52,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
-        final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
+        final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
         for (PackageUserKey puk : mPackages) {
             UserHandle user = puk.mUser;
 
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 59dd1b1..1916d23 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -22,6 +22,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
@@ -38,7 +39,7 @@
 /**
  * Handles changes due to shortcut manager updates (deep shortcut changes)
  */
-public class ShortcutsChangedTask extends BaseModelUpdateTask {
+public class ShortcutsChangedTask implements ModelUpdateTask {
 
     @NonNull
     private final String mPackageName;
@@ -61,8 +62,9 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
+        final LauncherAppState app = taskController.getApp();
         final Context context = app.getContext();
         // Find WorkspaceItemInfo's that have changed on the workspace.
         ArrayList<WorkspaceItemInfo> matchingWorkspaceItems = new ArrayList<>();
@@ -78,8 +80,8 @@
 
         if (!matchingWorkspaceItems.isEmpty()) {
             if (mShortcuts.isEmpty()) {
-                PackageManagerHelper packageManagerHelper = new PackageManagerHelper(
-                        app.getContext());
+                PackageManagerHelper packageManagerHelper =
+                        PackageManagerHelper.INSTANCE.get(context);
                 // Verify that the app is indeed installed.
                 if (!packageManagerHelper.isAppInstalled(mPackageName, mUser)
                         && !packageManagerHelper.isAppArchivedForUser(mPackageName, mUser)) {
@@ -115,9 +117,9 @@
                         });
             }
 
-            bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
+            taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
             if (!nonPinnedIds.isEmpty()) {
-                deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(
+                taskController.deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(
                         nonPinnedIds.stream()
                                 .map(id -> new ShortcutKey(mPackageName, mUser, id))
                                 .collect(Collectors.toSet())),
@@ -128,7 +130,7 @@
         if (mUpdateIdMap) {
             // Update the deep shortcut map if the list of ids has changed for an activity.
             dataModel.updateDeepShortcutCounts(mPackageName, mUser, mShortcuts);
-            bindDeepShortcuts(dataModel);
+            taskController.bindDeepShortcuts(dataModel);
         }
     }
 }
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 63ca35b..3dc5ff3 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -24,6 +24,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
@@ -40,7 +41,7 @@
 /**
  * Task to handle changing of lock state of the user
  */
-public class UserLockStateChangedTask extends BaseModelUpdateTask {
+public class UserLockStateChangedTask implements ModelUpdateTask {
 
     @NonNull
     private final UserHandle mUser;
@@ -52,8 +53,9 @@
     }
 
     @Override
-    public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
-            @NonNull final AllAppsList apps) {
+    public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+            @NonNull AllAppsList apps) {
+        LauncherAppState app = taskController.getApp();
         Context context = app.getContext();
 
         HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
@@ -98,9 +100,10 @@
                 }
             });
         }
-        bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
+        taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
         if (!removedKeys.isEmpty()) {
-            deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys),
+            taskController.deleteAndBindComponentsRemoved(
+                    ItemInfoMatcher.ofShortcutKeys(removedKeys),
                     "removed during unlock because it's no longer available"
                             + " (possibly due to clear data)");
         }
@@ -118,6 +121,6 @@
                     null, mUser,
                     new ShortcutRequest(context, mUser).query(ShortcutRequest.ALL));
         }
-        bindDeepShortcuts(dataModel);
+        taskController.bindDeepShortcuts(dataModel);
     }
 }
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 91ce5ea..5e0edb3 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -118,8 +118,8 @@
         Map<PackageUserKey, List<WidgetItem>> packagesToWidgets = new HashMap<>();
         mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) -> {
             List<WidgetItem> widgets = widgetsAndShortcuts.stream()
-                        .filter(item -> item.widgetInfo != null)
-                        .collect(toList());
+                    .filter(item -> item.widgetInfo != null)
+                    .collect(toList());
             if (widgets.size() > 0) {
                 packagesToWidgets.put(
                         new PackageUserKey(packageItemInfo.packageName, packageItemInfo.user),
@@ -239,20 +239,45 @@
         }
     }
 
+    private PackageItemInfo createPackageItemInfo(
+            ComponentName providerName,
+            UserHandle user,
+            int category
+    ) {
+        if (category == NO_CATEGORY) {
+            return new PackageItemInfo(providerName.getPackageName(), user);
+        } else {
+            return new PackageItemInfo("" , category, user);
+        }
+    }
+
+    private IntSet getCategories(ComponentName providerName, Context context) {
+        IntSet categories = WidgetSections.getWidgetsToCategory(context).get(providerName);
+        if (categories != null) {
+            return categories;
+        }
+        categories = new IntSet();
+        categories.add(NO_CATEGORY);
+        return categories;
+    }
+
     public WidgetItem getWidgetProviderInfoByProviderName(
-            ComponentName providerName, UserHandle user) {
+            ComponentName providerName, UserHandle user, Context context) {
         if (!WIDGETS_ENABLED) {
             return null;
         }
-        List<WidgetItem> widgetsList = mWidgetsList.get(
-                new PackageItemInfo(providerName.getPackageName(), user));
-        if (widgetsList == null) {
-            return null;
-        }
+        IntSet categories = getCategories(providerName, context);
 
-        for (WidgetItem item : widgetsList) {
-            if (item.componentName.equals(providerName)) {
-                return item;
+        // Checking if we have a provider in any of the categories.
+        for (Integer category: categories) {
+            PackageItemInfo key = createPackageItemInfo(providerName, user, category);
+            List<WidgetItem> widgets = mWidgetsList.get(key);
+            if (widgets != null) {
+                return widgets.stream().filter(
+                                item -> item.componentName.equals(providerName)
+                        )
+                        .findFirst()
+                        .orElse(null);
             }
         }
         return null;
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index ee45c0f..90e47d6 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -34,6 +34,7 @@
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
 import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.data.AppInfo
 import com.android.launcher3.model.data.AppPairInfo
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.IconRequestInfo
@@ -41,6 +42,7 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.pm.PackageInstallInfo
+import com.android.launcher3.pm.UserCache
 import com.android.launcher3.shortcuts.ShortcutKey
 import com.android.launcher3.util.ApiWrapper
 import com.android.launcher3.util.ComponentKey
@@ -60,6 +62,7 @@
 class WorkspaceItemProcessor(
     private val c: LoaderCursor,
     private val memoryLogger: LoaderMemoryLogger?,
+    private val userCache: UserCache,
     private val userManagerState: UserManagerState,
     private val launcherApps: LauncherApps,
     private val pendingPackages: MutableSet<PackageUserKey>,
@@ -181,6 +184,9 @@
                 }
             }
         }
+        if (intent.`package` == null) {
+            intent.`package` = targetPkg
+        }
         // else if cn == null => can't infer much, leave it
         // else if !validPkg => could be restored icon or missing sd-card
         when {
@@ -326,12 +332,12 @@
             }
             val activityInfo = c.launcherActivityInfo
             if (activityInfo != null) {
-                if (ApiWrapper.INSTANCE.get(app.context).isNonResizeableActivity(activityInfo)) {
-                    info.status = info.status or WorkspaceItemInfo.FLAG_NON_RESIZEABLE
-                }
-                info.setProgressLevel(
-                    PackageManagerHelper.getLoadingProgress(activityInfo),
-                    PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
+                AppInfo.updateRuntimeFlagsForActivityTarget(
+                    info,
+                    activityInfo,
+                    userCache.getUserInfo(c.user),
+                    ApiWrapper.INSTANCE[app.context],
+                    pmHelper
                 )
             }
             if (
diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
index 929f698..1a6d178 100644
--- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
+++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
@@ -15,8 +15,8 @@
  */
 package com.android.launcher3.model;
 
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
 
 import android.util.LongSparseArray;
 
@@ -68,7 +68,7 @@
         // First check the preferred screen.
         IntSet screensToExclude = new IntSet();
         if (FeatureFlags.QSB_ON_FIRST_SCREEN
-                && !shouldShowFirstPageWidget()) {
+                && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             screensToExclude.add(FIRST_SCREEN_ID);
         }
 
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 93ba619..a4281f8 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -35,6 +35,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.UserIconInfo;
 
@@ -89,10 +90,12 @@
      */
     public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
         this(info, UserCache.INSTANCE.get(context).getUserInfo(user),
+                ApiWrapper.INSTANCE.get(context), PackageManagerHelper.INSTANCE.get(context),
                 context.getSystemService(UserManager.class).isQuietModeEnabled(user));
     }
 
-    public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo, boolean quietModeEnabled) {
+    public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo,
+            ApiWrapper apiWrapper, PackageManagerHelper pmHelper, boolean quietModeEnabled) {
         this.componentName = info.getComponentName();
         this.container = CONTAINER_ALL_APPS;
         this.user = userIconInfo.user;
@@ -102,7 +105,7 @@
             runtimeStatusFlags |= FLAG_DISABLED_QUIET_USER;
         }
         uid = info.getApplicationInfo().uid;
-        updateRuntimeFlagsForActivityTarget(this, info, userIconInfo);
+        updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper, pmHelper);
     }
 
     public AppInfo(AppInfo info) {
@@ -175,14 +178,27 @@
         return componentName;
     }
 
-    public static void updateRuntimeFlagsForActivityTarget(
-            ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo) {
+    /**
+     * Updates the runtime status flags for the given info based on the state of the specified
+     * activity.
+     */
+    public static boolean updateRuntimeFlagsForActivityTarget(
+            ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo,
+            ApiWrapper apiWrapper, PackageManagerHelper pmHelper) {
+        final int oldProgressLevel = info.getProgressLevel();
+        final int oldRuntimeStatusFlags = info.runtimeStatusFlags;
         ApplicationInfo appInfo = lai.getApplicationInfo();
         if (PackageManagerHelper.isAppSuspended(appInfo)) {
             info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
+        } else {
+            info.runtimeStatusFlags &= ~FLAG_DISABLED_SUSPENDED;
         }
-        if (Flags.enableSupportForArchiving() && lai.getActivityInfo().isArchived) {
-            info.runtimeStatusFlags |= FLAG_ARCHIVED;
+        if (Flags.enableSupportForArchiving()) {
+            if (lai.getActivityInfo().isArchived) {
+                info.runtimeStatusFlags |= FLAG_ARCHIVED;
+            } else {
+                info.runtimeStatusFlags &= ~FLAG_ARCHIVED;
+            }
         }
         info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
                 ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
@@ -190,6 +206,8 @@
         if (Flags.privateSpaceRestrictAccessibilityDrag()) {
             if (userIconInfo.isPrivate()) {
                 info.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+            } else {
+                info.runtimeStatusFlags &= ~FLAG_NOT_PINNABLE;
             }
         }
 
@@ -197,6 +215,11 @@
         info.setProgressLevel(
                 PackageManagerHelper.getLoadingProgress(lai),
                 PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+        info.setNonResizeable(apiWrapper.isNonResizeableActivity(lai));
+        info.setSupportsMultiInstance(
+                pmHelper.supportsMultiInstance(lai.getComponentName()));
+        return (oldProgressLevel != info.getProgressLevel())
+                || (oldRuntimeStatusFlags != info.runtimeStatusFlags);
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
index 3dbd45b..2eb6154 100644
--- a/src/com/android/launcher3/model/data/AppPairInfo.kt
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -73,8 +73,8 @@
         val isTablet =
             (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet
         return Pair(
-            isTablet || !getFirstApp().hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE),
-            isTablet || !getSecondApp().hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE)
+            isTablet || !getFirstApp().isNonResizeable(),
+            isTablet || !getSecondApp().isNonResizeable()
         )
     }
 
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 8c3efd7..b82d0a0 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -73,6 +73,7 @@
  * Represents an item in the launcher.
  */
 public class ItemInfo {
+    private static final String TAG = "ItemInfo";
 
     public static final boolean DEBUG = false;
     public static final int NO_ID = -1;
@@ -285,7 +286,7 @@
     @Override
     @NonNull
     public final String toString() {
-        return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+        return TAG + "(" + dumpProperties() + ")";
     }
 
     @NonNull
@@ -427,12 +428,10 @@
     @NonNull
     protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
-        UserIconInfo info = getUserInfo();
-        itemBuilder.setIsWork(info != null && info.isWork());
-        itemBuilder.setUserType(getUserType(info));
-        SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate();
-        boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0);
-        itemBuilder.setIsKidsMode(isKidsMode);
+        SettingsCache.INSTANCE.executeIfCreated(cache ->
+                itemBuilder.setIsKidsMode(cache.getValue(NAV_BAR_KIDS_MODE, 0)));
+        UserCache.INSTANCE.executeIfCreated(cache ->
+                itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
         itemBuilder.setRank(rank);
         return itemBuilder;
     }
@@ -526,15 +525,6 @@
         this.title = title;
     }
 
-    private UserIconInfo getUserInfo() {
-        UserCache userCache = UserCache.INSTANCE.getNoCreate();
-        if (userCache == null) {
-            return null;
-        }
-
-        return userCache.getUserInfo(user);
-    }
-
     private int getUserType(UserIconInfo info) {
         if (info == null) {
             return SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_UNKNOWN;
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 3a74ff2..6ac44ff 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -122,6 +122,16 @@
     public static final int FLAG_ARCHIVED = 1 << 14;
 
     /**
+     * Flag indicating whether the package related to the item & user does not support resizing.
+     */
+    public static final int FLAG_NOT_RESIZEABLE = 1 << 15;
+
+    /**
+     * Flag indicating whether the package related to the item & user supports multiple instances.
+     */
+    public static final int FLAG_SUPPORTS_MULTI_INSTANCE = 1 << 16;
+
+    /**
      * Status associated with the system state of the underlying item. This is calculated every
      * time a new info is created and not persisted on the disk.
      */
@@ -246,6 +256,42 @@
         }
     }
 
+    /**
+     * Sets whether this app info supports multi-instance.
+     */
+    protected void setSupportsMultiInstance(boolean supportsMultiInstance) {
+        if (supportsMultiInstance) {
+            runtimeStatusFlags |= FLAG_SUPPORTS_MULTI_INSTANCE;
+        } else {
+            runtimeStatusFlags &= ~FLAG_SUPPORTS_MULTI_INSTANCE;
+        }
+    }
+
+    /**
+     * Returns whether this app info supports multi-instance.
+     */
+    public boolean supportsMultiInstance() {
+        return (runtimeStatusFlags & FLAG_SUPPORTS_MULTI_INSTANCE) != 0;
+    }
+
+    /**
+     * Sets whether this app info is non-resizeable.
+     */
+    public void setNonResizeable(boolean nonResizeable) {
+        if (nonResizeable) {
+            runtimeStatusFlags |= FLAG_NOT_RESIZEABLE;
+        } else {
+            runtimeStatusFlags &= ~FLAG_NOT_RESIZEABLE;
+        }
+    }
+
+    /**
+     * Returns whether this app info is resizeable.
+     */
+    public boolean isNonResizeable() {
+        return (runtimeStatusFlags & FLAG_NOT_RESIZEABLE) != 0;
+    }
+
     /** Creates an intent to that launches the app store at this app's page. */
     @Nullable
     public Intent getMarketIntent(Context context) {
@@ -278,4 +324,11 @@
         drawable.setIsDisabled(isDisabled());
         return drawable;
     }
+
+    @Override
+    protected String dumpProperties() {
+        return super.dumpProperties()
+                + " supportsMultiInstance=" + supportsMultiInstance()
+                + " nonResizeable=" + isNonResizeable();
+    }
 }
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 5ae7003..2c533ac 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -75,12 +75,6 @@
     public static final int FLAG_START_FOR_RESULT = 1 << 4;
 
     /**
-     * The app is flagged non-resizeable, meaning that it does not support multi-window on small
-     * screens.
-     */
-    public static final int FLAG_NON_RESIZEABLE = 1 << 5;
-
-    /**
      * The intent used to start the application.
      */
     @NonNull
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 4a3318e..e66f496 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -32,7 +32,6 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.util.IntArray;
@@ -41,6 +40,7 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -52,7 +52,7 @@
  * Utility class to tracking install sessions
  */
 @SuppressWarnings("NewApi")
-public class InstallSessionHelper {
+public class InstallSessionHelper implements SafeCloseable {
 
     @NonNull
     private static final String LOG = "InstallSessionHelper";
@@ -89,6 +89,9 @@
         mLauncherApps = context.getSystemService(LauncherApps.class);
     }
 
+    @Override
+    public void close() { }
+
     @WorkerThread
     @NonNull
     private IntSet getPromiseIconIds() {
@@ -168,7 +171,7 @@
         synchronized (mSessionVerifiedMap) {
             if (!mSessionVerifiedMap.containsKey(pkg)) {
                 boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg)
-                        || new PackageManagerHelper(mAppContext)
+                        || PackageManagerHelper.INSTANCE.get(mAppContext)
                                 .getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
                 mSessionVerifiedMap.put(pkg, hasSystemFlag);
             }
@@ -242,7 +245,7 @@
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
                 && !TextUtils.isEmpty(sessionInfo.getAppLabel())
-                && !new PackageManagerHelper(mAppContext).isAppInstalled(
+                && !PackageManagerHelper.INSTANCE.get(mAppContext).isAppInstalled(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
     }
 
diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java
index 1797c1f..23d3b61 100644
--- a/src/com/android/launcher3/pm/PackageInstallInfo.java
+++ b/src/com/android/launcher3/pm/PackageInstallInfo.java
@@ -22,6 +22,7 @@
 import androidx.annotation.NonNull;
 
 public final class PackageInstallInfo {
+    private static final String TAG = "PackageInstallInfo";
 
     public static final int STATUS_INSTALLED = 0;
     public static final int STATUS_INSTALLING = 1;
@@ -61,7 +62,7 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+        return TAG + "(" + dumpProperties() + ")";
     }
 
     private String dumpProperties() {
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 185e0b5..b7b557d 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -24,6 +24,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
@@ -81,6 +82,9 @@
     @NonNull
     private Map<UserHandle, UserIconInfo> mUserToSerialMap;
 
+    @NonNull
+    private Map<UserHandle, List<String>> mUserToPreInstallAppMap;
+
     private UserCache(Context context) {
         mContext = context;
         mUserToSerialMap = Collections.emptyMap();
@@ -120,6 +124,20 @@
     @WorkerThread
     private void updateCache() {
         mUserToSerialMap = ApiWrapper.INSTANCE.get(mContext).queryAllUsers();
+        mUserToPreInstallAppMap = fetchPreInstallApps();
+    }
+
+    @WorkerThread
+    private Map<UserHandle, List<String>> fetchPreInstallApps() {
+        Map<UserHandle, List<String>> userToPreInstallApp = new ArrayMap<>();
+        mUserToSerialMap.forEach((userHandle, userIconInfo) -> {
+            // Fetch only for private profile, as other profiles have no usages yet.
+            List<String> preInstallApp = userIconInfo.isPrivate()
+                    ? ApiWrapper.INSTANCE.get(mContext).getPreInstalledSystemPackages(userHandle)
+                    : new ArrayList<>();
+            userToPreInstallApp.put(userHandle, preInstallApp);
+        });
+        return userToPreInstallApp;
     }
 
     /**
@@ -172,6 +190,15 @@
     }
 
     /**
+     * Returns the pre-installed apps for a user.
+     */
+    @NonNull
+    public List<String> getPreInstallApps(UserHandle user) {
+        List<String> preInstallApp = mUserToPreInstallAppMap.get(user);
+        return preInstallApp == null ? new ArrayList<>() : preInstallApp;
+    }
+
+    /**
      * Get a non-themed {@link UserBadgeDrawable} based on the provided {@link UserHandle}.
      */
     @Nullable
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 436aa51..575052c 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -84,11 +84,12 @@
      * @param width        of the arrow.
      * @param height       of the arrow.
      * @param radius       of the tip of the arrow.
-     * @param isPointingLeft or not.
+     * @param isHorizontal or not.
+     * @param isLeftOrTop  or not.
      * @param color        to draw the triangle.
      */
-    public RoundedArrowDrawable(float width, float height, float radius, boolean isPointingLeft,
-            int color) {
+    private RoundedArrowDrawable(float width, float height, float radius, boolean isHorizontal,
+            boolean isLeftOrTop, int color) {
         mPath = new Path();
         mPaint = new Paint();
         mPaint.setColor(color);
@@ -98,10 +99,47 @@
         // Make the drawable with the triangle pointing down...
         addDownPointingRoundedTriangleToPath(width, height, radius, mPath);
 
-        // ... then rotate it to the side it needs to point.
-        Matrix pathTransform = new Matrix();
-        pathTransform.setRotate(isPointingLeft ? 90 : -90, width * 0.5f, height * 0.5f);
-        mPath.transform(pathTransform);
+        if (isHorizontal || isLeftOrTop) {
+            // ... then rotate it to the side it needs to point.
+            Matrix pathTransform = new Matrix();
+            int rotationAngle;
+            if (isHorizontal) {
+                rotationAngle = isLeftOrTop ? 90 : -90;
+            } else {
+                // it could only be vertical arrow pointing up
+                rotationAngle = 180;
+            }
+            pathTransform.setRotate(rotationAngle, width * 0.5f, height * 0.5f);
+            mPath.transform(pathTransform);
+        }
+    }
+
+    /**
+     * factory method for an arrow that points to the left or right.
+     *
+     * @param width          of the arrow.
+     * @param height         of the arrow.
+     * @param radius         of the tip of the arrow.
+     * @param isPointingLeft or not.
+     * @param color          to draw the triangle.
+     */
+    public static RoundedArrowDrawable createHorizontalRoundedArrow(float width, float height,
+            float radius, boolean isPointingLeft, int color) {
+        return new RoundedArrowDrawable(width, height, radius, true, isPointingLeft, color);
+    }
+
+    /**
+     * factory method for an arrow that points to the left or right.
+     *
+     * @param width        of the arrow.
+     * @param height       of the arrow.
+     * @param radius       of the tip of the arrow.
+     * @param isPointingUp or not.
+     * @param color        to draw the triangle.
+     */
+    public static RoundedArrowDrawable createVerticalRoundedArrow(float width, float height,
+            float radius, boolean isPointingUp, int color) {
+        return new RoundedArrowDrawable(width, height, radius, false, isPointingUp, color);
     }
 
     @Override
@@ -129,6 +167,14 @@
         mPaint.setColorFilter(colorFilter);
     }
 
+    /**
+     * Set shadow layer to internal {@link Paint#setShadowLayer(float, float, float, int) paint}
+     * object
+     */
+    public void setShadowLayer(float shadowBlur, float dx, float dy, int shadowColor) {
+        mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
+    }
+
     private static void addDownPointingRoundedTriangleToPath(float width, float height,
             float radius, Path path) {
         // Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f56d732..6005573 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -181,8 +181,8 @@
         public void onClick(View view) {
             dismissTaskMenuView();
             Rect sourceBounds = Utilities.getViewBounds(view);
-            new PackageManagerHelper(view.getContext()).startDetailsActivityForInfo(
-                    mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
+            PackageManagerHelper.startDetailsActivityForInfo(view.getContext(), mItemInfo,
+                    sourceBounds, ActivityOptions.makeBasic().toBundle());
             mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
                     .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
         }
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index b992a92..3ae643e 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.PackageManagerHelper;
 
 /**
  * A set of utility methods for Launcher DB used for DB updates and migration.
@@ -107,9 +108,11 @@
         Cursor c = db.query(
                 Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null);
         UserManagerState ums = new UserManagerState();
+        PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
         ums.init(UserCache.INSTANCE.get(context),
                 context.getSystemService(UserManager.class));
-        LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, null);
+        LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper,
+                null);
         IntSet deletedShortcuts = new IntSet();
 
         while (lc.moveToNext()) {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index d5f1e18..a4ff29f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -526,10 +526,7 @@
         }
 
         logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
-        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app != null) {
-            app.getModel().forceReload();
-        }
+        LauncherAppState.INSTANCE.executeIfCreated(app -> app.getModel().forceReload());
     }
 
     private static void logDatabaseWidgetInfo(ModelDbController controller) {
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index f0f376f..8e53aff 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -20,7 +20,7 @@
 import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
 import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;
 
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -292,7 +292,8 @@
         }
 
         public boolean isQsbEnabled() {
-            return FeatureFlags.QSB_ON_FIRST_SCREEN && !shouldShowFirstPageWidget();
+            return FeatureFlags.QSB_ON_FIRST_SCREEN
+                    && !SHOULD_SHOW_FIRST_PAGE_WIDGET;
         }
 
         protected Bundle createBindOptions() {
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 43027da..6d6b3b6 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -26,7 +26,9 @@
 import com.android.launcher3.util.CancellableTask
 import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
+import com.android.launcher3.util.Themes
 import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.views.ActivityContext.ActivityContextDelegate
 
 const val PREINFLATE_ICONS_ROW_COUNT = 4
 const val EXTRA_ICONS_COUNT = 2
@@ -52,12 +54,28 @@
             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
+        // AssetManager obj that is associated with the launcher context on the main thread.
+        val allAppsPreInflationContext =
+            ActivityContextDelegate(
+                context.createConfigurationContext(context.resources.configuration),
+                Themes.getActivityThemeRes(context),
+                context
+            )
+
         // Because we perform onCreateViewHolder() on worker thread, we need a separate
         // adapter/inflator object as they are not thread-safe. Note that the adapter
         // just need to perform onCreateViewHolder(parent, VIEW_TYPE_ICON) so it doesn't need
         // data source information.
         val adapter: RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> =
-            object : BaseAllAppsAdapter<T>(context, context.appsView.layoutInflater, null, null) {
+            object :
+                BaseAllAppsAdapter<T>(
+                    context,
+                    context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext),
+                    null,
+                    null
+                ) {
                 override fun setAppsPerRow(appsPerRow: Int) = Unit
                 override fun getLayoutManager(): RecyclerView.LayoutManager? = null
             }
diff --git a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
index 7502a43..2c3035f 100644
--- a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
@@ -135,7 +135,7 @@
         hotseatQsbSpace.fixedSize + edgePadding.fixedSize <= maxAvailableSize
 
     private fun logError(message: String) {
-        Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+        Log.e(LOG_TAG, "$LOG_TAG #isValid - $message - $this")
     }
 
     companion object {
diff --git a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
index a4b25e5..ef9b7df 100644
--- a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
@@ -31,7 +31,7 @@
             groupOfSpecs
                 .onEach { group ->
                     check(group.widthSpecs.isEmpty() && group.heightSpecs.isNotEmpty()) {
-                        "${this::class.simpleName} is invalid, only heightSpecs are allowed - " +
+                        "$LOG_TAG is invalid, only heightSpecs are allowed - " +
                             "width list size = ${group.widthSpecs.size}; " +
                             "height list size = ${group.heightSpecs.size}."
                     }
@@ -65,6 +65,7 @@
     }
 
     companion object {
+        private const val LOG_TAG = "ResponsiveCellSpecsProvider"
         @JvmStatic
         fun create(resourceHelper: ResourceHelper): ResponsiveCellSpecsProvider {
             val parser = ResponsiveSpecsParser(resourceHelper)
@@ -137,11 +138,11 @@
     }
 
     private fun logError(message: String) {
-        Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+        Log.e(LOG_TAG, "$LOG_TAG#isValid - $message - $this")
     }
 
     companion object {
-        private const val LOG_TAG = "CellSpec"
+        const val LOG_TAG = "CellSpec"
     }
 }
 
@@ -182,6 +183,7 @@
     )
 
     companion object {
+        private const val LOG_TAG = "CalculatedCellSpec"
         private fun getCalculatedValue(
             availableSpace: Int,
             spec: SizeSpec,
@@ -191,10 +193,10 @@
     }
 
     override fun toString(): String {
-        return "${this::class.simpleName}(" +
+        return "$LOG_TAG(" +
             "availableSpace=$availableSpace, iconSize=$iconSize, " +
             "iconTextSize=$iconTextSize, iconDrawablePadding=$iconDrawablePadding, " +
-            "${spec::class.simpleName}.maxAvailableSize=${spec.maxAvailableSize}" +
+            "${CellSpec.LOG_TAG}.maxAvailableSize=${spec.maxAvailableSize}" +
             ")"
     }
 }
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpec.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
index 65e0b32..e69324d 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpec.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -154,7 +154,7 @@
     }
 
     private fun logError(message: String) {
-        Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+        Log.e(LOG_TAG, "$LOG_TAG#isValid - $message - $this")
     }
 
     enum class DimensionType {
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
index 67eaac0..654608d 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
@@ -40,7 +40,7 @@
             groupOfSpecs
                 .onEach { group ->
                     check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) {
-                        "${this::class.simpleName} is incomplete - " +
+                        "$LOG_TAG is incomplete - " +
                             "width list size = ${group.widthSpecs.size}; " +
                             "height list size = ${group.heightSpecs.size}."
                     }
@@ -124,6 +124,7 @@
     }
 
     companion object {
+        private const val LOG_TAG = "ResponsiveSpecsProvider"
         @JvmStatic
         fun create(
             resourceHelper: ResourceHelper,
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index c10d85e..52ce4e8 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -41,7 +41,6 @@
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback;
 import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback;
@@ -53,9 +52,7 @@
 import com.android.launcher3.LauncherFiles;
 import com.android.launcher3.R;
 import com.android.launcher3.states.RotationHelper;
-import com.android.launcher3.uioverrides.flags.DeveloperOptionsUI;
 import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.SettingsCache;
 
 /**
@@ -255,12 +252,6 @@
                         preference.setOrder(0);
                     }
                     return mDeveloperOptionsEnabled;
-                case "pref_developer_flags":
-                    if (mDeveloperOptionsEnabled && preference instanceof PreferenceCategory pc) {
-                        Executors.MAIN_EXECUTOR.post(() -> new DeveloperOptionsUI(this, pc));
-                        return true;
-                    }
-                    return false;
             }
 
             return true;
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 51bc339..eea1a7d 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -51,7 +51,7 @@
 public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
 
     public static final String TAG = "StateManager";
-    // b/279059025
+    // b/279059025, b/325463989
     private static final boolean DEBUG = true;
 
     private final AnimationState mConfig = new AnimationState();
@@ -240,16 +240,8 @@
     private void goToState(
             STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
         if (DEBUG) {
-            String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
-            String truncatedTrace =
-                    Arrays.stream(stackTrace.split("\\n"))
-                            .limit(5)
-                            .skip(1) // Removes the line "java.lang.Exception: tracing state
-                            // transition"
-                            .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
-                            .collect(Collectors.joining("\n"));
             Log.d(TAG, "goToState - fromState: " + mState + ", toState: " + state
-                    + ", partial trace:\n" + truncatedTrace);
+                    + ", partial trace:\n" + getTrimmedStackTrace("StateManager.goToState"));
         }
 
         animated &= areAnimatorsEnabled();
@@ -336,17 +328,9 @@
     public AnimatorSet createAtomicAnimation(
             STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
         if (DEBUG) {
-            String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
-            String truncatedTrace =
-                    Arrays.stream(stackTrace.split("\\n"))
-                            .limit(5)
-                            .skip(1) // Removes the line "java.lang.Exception: tracing state
-                            // transition"
-                            .filter(traceLine -> !traceLine.contains(
-                                    "StateManager.createAtomicAnimation"))
-                            .collect(Collectors.joining("\n"));
             Log.d(TAG, "createAtomicAnimation - fromState: " + fromState + ", toState: " + toState
-                    + ", partial trace:\n" + truncatedTrace);
+                    + ", partial trace:\n" + getTrimmedStackTrace(
+                            "StateManager.createAtomicAnimation"));
         }
 
         PendingAnimation builder = new PendingAnimation(config.duration);
@@ -481,7 +465,8 @@
      */
     public void cancelAnimation() {
         if (DEBUG && mConfig.currentAnimation != null) {
-            Log.d(TAG, "cancelAnimation - with ongoing animation");
+            Log.d(TAG, "cancelAnimation - with ongoing animation"
+                    + ", partial trace:\n" + getTrimmedStackTrace("StateManager.cancelAnimation"));
         }
         mConfig.reset();
         // It could happen that a new animation is set as a result of an endListener on the
@@ -579,6 +564,15 @@
         mConfig.playbackController = null;
     }
 
+    private String getTrimmedStackTrace(String callingMethodName) {
+        String stackTrace = Log.getStackTraceString(new Exception());
+        return Arrays.stream(stackTrace.split("\\n"))
+                .skip(2) // Removes the line "java.lang.Exception" and "getTrimmedStackTrace".
+                .filter(traceLine -> !traceLine.contains(callingMethodName))
+                .limit(3)
+                .collect(Collectors.joining("\n"));
+    }
+
     private class StartAnimRunnable implements Runnable {
 
         private final AnimatorSet mAnim;
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index d5c9b9f..db2a6e0 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -94,13 +94,10 @@
 
     protected Context mContext;
     protected DeviceProfile mDeviceProfile;
-    protected LauncherAppState mLauncherAppState;
 
     public void init(Context context) {
         mContext = context;
-        mDeviceProfile = InvariantDeviceProfile.INSTANCE.
-                get(context).getDeviceProfile(context);
-        mLauncherAppState = LauncherAppState.getInstanceNoCreate();
+        mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context);
         if (sActivityLifecycleCallbacks == null) {
             sActivityLifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
                 @Override
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 9aed4eb..50f98f2 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -57,7 +57,7 @@
     protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
 
     protected final AnimatorListener mClearStateOnCancelListener =
-            newCancelListener(this::clearState);
+            newCancelListener(this::clearState, /* isSingleUse = */ false);
     private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
 
     protected int mStartContainerType;
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 0ed6ea0..f46dcd3 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -84,7 +84,8 @@
  */
 public class ItemClickHandler {
 
-    private static final String TAG = ItemClickHandler.class.getSimpleName();
+    private static final String TAG = "ItemClickHandler";
+    private static final boolean DEBUG = true;
 
     /**
      * Instance used for click handling on items
@@ -110,7 +111,19 @@
             startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
         } else if (tag instanceof LauncherAppWidgetInfo) {
             if (v instanceof PendingAppWidgetHostView) {
+                if (DEBUG) {
+                    String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage();
+                    Log.d(TAG, "onClick: PendingAppWidgetHostView clicked for"
+                            + " package=" + targetPackage);
+                }
                 onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
+            } else {
+                if (DEBUG) {
+                    String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage();
+                    Log.d(TAG, "onClick: LauncherAppWidgetInfo clicked,"
+                            + " but not instance of PendingAppWidgetHostView. Returning."
+                            + " package=" + targetPackage);
+                }
             }
         } else if (tag instanceof ItemClickProxy) {
             ((ItemClickProxy) tag).onItemClicked(v);
@@ -120,6 +133,10 @@
                     launcher.getString(R.string.long_accessible_way_to_add_shortcut));
             Snackbar.show(launcher, msg, null);
         } else if (tag instanceof PendingAddWidgetInfo) {
+            if (DEBUG) {
+                String targetPackage = ((PendingAddWidgetInfo) tag).getTargetPackage();
+                Log.d(TAG, "onClick: PendingAddWidgetInfo clicked for package=" + targetPackage);
+            }
             CharSequence msg = Utilities.wrapForTts(
                     launcher.getText(R.string.long_press_widget_to_add),
                     launcher.getString(R.string.long_accessible_way_to_add));
@@ -199,6 +216,9 @@
             LauncherAppWidgetProviderInfo appWidgetInfo = new WidgetManagerHelper(launcher)
                     .findProvider(info.providerName, info.user);
             if (appWidgetInfo == null) {
+                Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup,"
+                        + " but LauncherAppWidgetProviderInfo was null. Returning."
+                        + " component=" + info.getTargetComponent());
                 return;
             }
             WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
@@ -206,6 +226,10 @@
             if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
                 if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
                     // This should not happen, as we make sure that an Id is allocated during bind.
+                    Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup,"
+                            + " and LauncherAppWidgetProviderInfo was found. However,"
+                            + " no appWidgetId was allocated. Returning."
+                            + " component=" + info.getTargetComponent());
                     return;
                 }
                 addFlowHandler.startBindFlow(launcher, info.appWidgetId, info,
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 95a0511..b2d0d75 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,9 +15,6 @@
  */
 package com.android.launcher3.util;
 
-import static com.android.launcher3.testing.shared.TestProtocol.GET_FROM_RECENTS_FAILURE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
-
 import android.util.Log;
 
 import androidx.annotation.Nullable;
@@ -46,9 +43,6 @@
 
     public void onActivityDestroyed(T activity) {
         if (mCurrentActivity.get() == activity) {
-            testLogD(GET_FROM_RECENTS_FAILURE,
-                    String.format("ActivityTracker.onActivityDestroyed this=%s, activity=%s",
-                            this, activity));
             mCurrentActivity.clear();
         }
     }
@@ -82,8 +76,6 @@
     }
 
     public boolean handleCreate(T activity) {
-        testLogD(GET_FROM_RECENTS_FAILURE,
-                String.format("ActivityTracker.handleCreate this=%s, activity=%s", this, activity));
         mCurrentActivity = new WeakReference<>(activity);
         return handleIntent(activity, false /* alreadyOnHome */);
     }
diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java
deleted file mode 100644
index adc3c7d..0000000
--- a/src/com/android/launcher3/util/BgObjectWithLooper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.util;
-
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.annotation.WorkerThread;
-
-import java.util.function.Consumer;
-
-/**
- * Utility class to define an object which does most of it's processing on a
- * dedicated background thread.
- */
-public abstract class BgObjectWithLooper {
-
-    /**
-     * Start initialization of the object
-     */
-    public final void initializeInBackground(String threadName) {
-        new Thread(this::runOnThread, threadName).start();
-    }
-
-    private void runOnThread() {
-        Looper.prepare();
-        onInitialized(Looper.myLooper());
-        Looper.loop();
-    }
-
-    /**
-     * Called on the background thread to handle initialization
-     */
-    @WorkerThread
-    protected abstract void onInitialized(Looper looper);
-
-    /**
-     * Helper method to create a content provider
-     */
-    protected static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) {
-        return new ContentObserver(handler) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                command.accept(uri);
-            }
-        };
-    }
-}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index ff95212..92fc38f 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -19,7 +19,12 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
+import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_DESKTOP_MODE_KEY;
+import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_IN_DESKTOP_MODE;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
@@ -47,6 +52,7 @@
 import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.InvariantDeviceProfile.DeviceType;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
@@ -84,10 +90,11 @@
     public static final int CHANGE_SUPPORTED_BOUNDS = 1 << 3;
     public static final int CHANGE_NAVIGATION_MODE = 1 << 4;
     public static final int CHANGE_TASKBAR_PINNING = 1 << 5;
+    public static final int CHANGE_DESKTOP_MODE = 1 << 6;
 
     public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION
             | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE
-            | CHANGE_TASKBAR_PINNING;
+            | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE;
 
     private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
     private static final String TARGET_OVERLAY_PACKAGE = "android";
@@ -141,16 +148,22 @@
     private void attachTaskbarPinningSharedPreferenceChangeListener(Context context) {
         mTaskbarPinningPreferenceChangeListener =
                 (sharedPreferences, key) -> {
-                    if (TASKBAR_PINNING_KEY.equals(key)
-                            && mInfo.mIsTaskbarPinned != LauncherPrefs.get(mContext).get(
-                            TASKBAR_PINNING)
-                    ) {
+                    LauncherPrefs prefs = LauncherPrefs.get(mContext);
+                    boolean isTaskbarPinningChanged = TASKBAR_PINNING_KEY.equals(key)
+                            && mInfo.mIsTaskbarPinned != prefs.get(TASKBAR_PINNING);
+                    boolean isTaskbarPinningDesktopModeChanged =
+                            TASKBAR_PINNING_DESKTOP_MODE_KEY.equals(key)
+                                    && mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get(
+                                    TASKBAR_PINNING_IN_DESKTOP_MODE);
+                    if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) {
                         handleInfoChange(mWindowContext.getDisplay());
                     }
                 };
 
         LauncherPrefs.get(context).addListener(
                 mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING);
+        LauncherPrefs.get(context).addListener(
+                mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING_IN_DESKTOP_MODE);
     }
 
     /**
@@ -168,6 +181,13 @@
     }
 
     /**
+     * Handles info change for desktop mode.
+     */
+    public static void handleInfoChangeForDesktopMode(Context context) {
+        INSTANCE.get(context).handleInfoChange(context.getDisplay());
+    }
+
+    /**
      * Enables transient taskbar status for tests.
      */
     @VisibleForTesting
@@ -188,6 +208,8 @@
         if (enableTaskbarPinning()) {
             LauncherPrefs.get(mContext).removeListener(
                     mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING);
+            LauncherPrefs.get(mContext).removeListener(
+                    mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING_IN_DESKTOP_MODE);
         }
         if (mWindowContext != null) {
             mWindowContext.unregisterComponentCallbacks(this);
@@ -305,9 +327,15 @@
             FileLog.w(TAG,
                     "(CHANGE_SUPPORTED_BOUNDS) perDisplayBounds: " + newInfo.mPerDisplayBounds);
         }
-        if (newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned) {
+        if ((newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned)
+                || (newInfo.mIsTaskbarPinnedInDesktopMode
+                    != oldInfo.mIsTaskbarPinnedInDesktopMode)) {
             change |= CHANGE_TASKBAR_PINNING;
         }
+        if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) {
+            change |= CHANGE_DESKTOP_MODE;
+        }
+
         if (DEBUG) {
             Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change));
         }
@@ -351,6 +379,9 @@
                 new ArrayMap<>();
 
         private final boolean mIsTaskbarPinned;
+        private final boolean mIsTaskbarPinnedInDesktopMode;
+
+        private final boolean mIsInDesktopMode;
 
         public Info(Context displayInfoContext) {
             /* don't need system overrides for external displays */
@@ -410,6 +441,9 @@
             }
 
             mIsTaskbarPinned = LauncherPrefs.get(displayInfoContext).get(TASKBAR_PINNING);
+            mIsTaskbarPinnedInDesktopMode = LauncherPrefs.get(displayInfoContext).get(
+                    TASKBAR_PINNING_IN_DESKTOP_MODE);
+            mIsInDesktopMode = wmProxy.isInDesktopMode();
         }
 
         /**
@@ -426,10 +460,14 @@
                 return sTransientTaskbarStatusForTests;
             }
             if (enableTaskbarPinning()) {
+                if (mIsInDesktopMode) {
+                    return !mIsTaskbarPinnedInDesktopMode;
+                }
                 return !mIsTaskbarPinned;
             }
             return true;
         }
+
         /**
          * Returns whether the taskbar is pinned in gesture navigation mode.
          */
@@ -437,6 +475,10 @@
             return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar();
         }
 
+        public boolean isInDesktopMode() {
+            return mIsInDesktopMode;
+        }
+
         /**
          * Returns {@code true} if the bounds represent a tablet.
          */
@@ -466,6 +508,23 @@
         public int getDensityDpi() {
             return densityDpi;
         }
+
+        public @DeviceType int getDeviceType() {
+            int flagPhone = 1 << 0;
+            int flagTablet = 1 << 1;
+
+            int type = supportedBounds.stream()
+                    .mapToInt(bounds -> isTablet(bounds) ? flagTablet : flagPhone)
+                    .reduce(0, (a, b) -> a | b);
+            if (type == (flagPhone | flagTablet)) {
+                // device has profiles supporting both phone and tablet modes
+                return TYPE_MULTI_DISPLAY;
+            } else if (type == flagTablet) {
+                return TYPE_TABLET;
+            } else {
+                return TYPE_PHONE;
+            }
+        }
     }
 
     /**
@@ -480,6 +539,7 @@
         appendFlag(result, change, CHANGE_SUPPORTED_BOUNDS, "CHANGE_SUPPORTED_BOUNDS");
         appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE");
         appendFlag(result, change, CHANGE_TASKBAR_PINNING, "CHANGE_TASKBAR_VARIANT");
+        appendFlag(result, change, CHANGE_DESKTOP_MODE, "CHANGE_DESKTOP_MODE");
         return result.toString();
     }
 
@@ -495,6 +555,8 @@
         pw.println("  densityDpi=" + info.densityDpi);
         pw.println("  navigationMode=" + info.navigationMode.name());
         pw.println("  isTaskbarPinned=" + info.mIsTaskbarPinned);
+        pw.println("  isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode);
+        pw.println("  isInDesktopMode=" + info.mIsInDesktopMode);
         pw.println("  currentSize=" + info.currentSize);
         info.mPerDisplayBounds.forEach((key, value) -> pw.println(
                 "  perDisplayBounds - " + key + ": " + value));
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index 1008ebb..fbdb5c2 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -33,7 +33,8 @@
  *
  * To allow customization for a particular resource, add them to dynamic_resources.xml
  */
-public class DynamicResource implements ResourceProvider, PluginListener<ResourceProvider> {
+public class DynamicResource implements
+        ResourceProvider, PluginListener<ResourceProvider>, SafeCloseable {
 
     private static final MainThreadInitializedObject<DynamicResource> INSTANCE =
             new MainThreadInitializedObject<>(DynamicResource::new);
@@ -48,6 +49,11 @@
     }
 
     @Override
+    public void close() {
+        PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
+    }
+
+    @Override
     public int getInt(@IntegerRes int resId) {
         return mContext.getResources().getInteger(resId);
     }
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
index 0a87594..94f9e4f 100644
--- a/src/com/android/launcher3/util/LockedUserState.kt
+++ b/src/com/android/launcher3/util/LockedUserState.kt
@@ -56,12 +56,16 @@
 
     private fun notifyUserUnlocked() {
         mUserUnlockedActions.executeAllAndDestroy()
-        mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+        Executors.THREAD_POOL_EXECUTOR.execute {
+            mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+        }
     }
 
     /** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */
     override fun close() {
-        mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+        Executors.THREAD_POOL_EXECUTOR.execute {
+            mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index b966d8e..1a0f9a0 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -28,17 +28,15 @@
 import com.android.launcher3.util.ResourceBasedOverride.Overrides;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
 
 /**
  * Utility class for defining singletons which are initiated on main thread.
  */
-public class MainThreadInitializedObject<T> {
+public class MainThreadInitializedObject<T extends SafeCloseable> {
 
     private final ObjectProvider<T> mProvider;
     private T mValue;
@@ -48,14 +46,14 @@
     }
 
     public T get(Context context) {
-        if (context instanceof SandboxContext sc) {
+        Context app = context.getApplicationContext();
+        if (app instanceof SandboxApplication sc) {
             return sc.getObject(this);
         }
 
         if (mValue == null) {
             if (Looper.myLooper() == Looper.getMainLooper()) {
-                mValue = TraceHelper.allowIpcs("main.thread.object",
-                        () -> mProvider.get(context.getApplicationContext()));
+                mValue = TraceHelper.allowIpcs("main.thread.object", () -> mProvider.get(app));
             } else {
                 try {
                     return MAIN_EXECUTOR.submit(() -> get(context)).get();
@@ -67,8 +65,18 @@
         return mValue;
     }
 
-    public T getNoCreate() {
-        return mValue;
+    /**
+     * Executes the callback is the value is already created
+     * @return true if the callback was executed, false otherwise
+     */
+    public boolean executeIfCreated(Consumer<T> callback) {
+        T v = mValue;
+        if (v != null) {
+            callback.accept(v);
+            return true;
+        } else {
+            return false;
+        }
     }
 
     @VisibleForTesting
@@ -79,8 +87,8 @@
     /**
      * Initializes a provider based on resource overrides
      */
-    public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride(
-            Class<T> clazz, int resourceId) {
+    public static <T extends ResourceBasedOverride & SafeCloseable> MainThreadInitializedObject<T>
+            forOverride(Class<T> clazz, int resourceId) {
         return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId));
     }
 
@@ -89,24 +97,36 @@
         T get(Context context);
     }
 
+    public interface SandboxApplication {
+
+        /**
+         * Find a cached object from mObjectMap if we have already created one. If not, generate
+         * an object using the provider.
+         */
+        <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object);
+
+        @UiThread
+        default <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
+            return object.mProvider.get((Context) this);
+        }
+    }
+
     /**
      * Abstract Context which allows custom implementations for
      * {@link MainThreadInitializedObject} providers
      */
-    public static class SandboxContext extends ContextWrapper {
+    public static class SandboxContext extends ContextWrapper implements SandboxApplication {
 
         private static final String TAG = "SandboxContext";
 
-        protected final Set<MainThreadInitializedObject> mAllowedObjects;
-        protected final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
-        protected final ArrayList<Object> mOrderedObjects = new ArrayList<>();
+        private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
+        private final ArrayList<SafeCloseable> mOrderedObjects = new ArrayList<>();
 
         private final Object mDestroyLock = new Object();
         private boolean mDestroyed = false;
 
-        public SandboxContext(Context base, MainThreadInitializedObject... allowedObjects) {
+        public SandboxContext(Context base) {
             super(base);
-            mAllowedObjects = new HashSet<>(Arrays.asList(allowedObjects));
         }
 
         @Override
@@ -118,20 +138,14 @@
             synchronized (mDestroyLock) {
                 // Destroy in reverse order
                 for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
-                    Object o = mOrderedObjects.get(i);
-                    if (o instanceof SafeCloseable) {
-                        ((SafeCloseable) o).close();
-                    }
+                    mOrderedObjects.get(i).close();
                 }
                 mDestroyed = true;
             }
         }
 
-        /**
-         * Find a cached object from mObjectMap if we have already created one. If not, generate
-         * an object using the provider.
-         */
-        protected <T> T getObject(MainThreadInitializedObject<T> object) {
+        @Override
+        public <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object) {
             synchronized (mDestroyLock) {
                 if (mDestroyed) {
                     Log.e(TAG, "Static object access with a destroyed context");
@@ -142,12 +156,6 @@
                 }
                 if (Looper.myLooper() == Looper.getMainLooper()) {
                     t = createObject(object);
-                    // Check if we've explicitly allowed the object or if it's a SafeCloseable,
-                    // it will get destroyed in onDestroy()
-                    if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
-                        throw new IllegalStateException("Leaking unknown objects "
-                                + object + "  " + object.mProvider + " " + t);
-                    }
                     mObjectMap.put(object, t);
                     mOrderedObjects.add(t);
                     return t;
@@ -161,17 +169,12 @@
             }
         }
 
-        @UiThread
-        protected <T> T createObject(MainThreadInitializedObject<T> object) {
-            return object.mProvider.get(this);
-        }
-
         /**
          * Put a value into mObjectMap, can be used to put mocked MainThreadInitializedObject
          * instances into SandboxContext.
          */
-        @VisibleForTesting
-        public <T> void putObject(MainThreadInitializedObject<T> object, T value) {
+        public <T extends SafeCloseable> void putObject(
+                MainThreadInitializedObject<T> object, T value) {
             mObjectMap.put(object, value);
         }
     }
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.kt b/src/com/android/launcher3/util/OnboardingPrefs.kt
index 370b4c8..ac6e97c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.kt
+++ b/src/com/android/launcher3/util/OnboardingPrefs.kt
@@ -76,7 +76,5 @@
     @JvmField
     val HOTSEAT_LONGPRESS_TIP_SEEN = backedUpItem("launcher.hotseat_longpress_tip_seen", false)
 
-    @JvmField
-    val TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN =
-        backedUpItem("launcher.taskbar_circle_to_search_edu_seen", false)
+    @JvmField val TASKBAR_SEARCH_EDU_SEEN = backedUpItem("launcher.taskbar_search_edu_seen", false)
 }
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 608bed7..f7c4df4 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.util;
 
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+import static android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI;
 
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -56,11 +57,15 @@
 /**
  * Utility methods using package manager
  */
-public class PackageManagerHelper {
+public class PackageManagerHelper implements SafeCloseable{
 
     private static final String TAG = "PackageManagerHelper";
 
     @NonNull
+    public static final MainThreadInitializedObject<PackageManagerHelper> INSTANCE =
+            new MainThreadInitializedObject<>(PackageManagerHelper::new);
+
+    @NonNull
     private final Context mContext;
 
     @NonNull
@@ -69,12 +74,19 @@
     @NonNull
     private final LauncherApps mLauncherApps;
 
+    private final String[] mLegacyMultiInstanceSupportedApps;
+
     public PackageManagerHelper(@NonNull final Context context) {
         mContext = context;
         mPm = context.getPackageManager();
         mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class));
+        mLegacyMultiInstanceSupportedApps = mContext.getResources().getStringArray(
+                R.array.config_appsSupportMultiInstancesSplit);
     }
 
+    @Override
+    public void close() { }
+
     /**
      * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
      * guarantee that the app is on SD card.
@@ -152,11 +164,23 @@
         }
     }
 
+    /**
+     * Returns the preferred launch activity intent for a given package.
+     */
     @Nullable
     public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) {
+        LauncherActivityInfo info = getAppLaunchInfo(pkg, user);
+        return info != null ? AppInfo.makeLaunchIntent(info) : null;
+    }
+
+    /**
+     * Returns the preferred launch activity for a given package.
+     */
+    @Nullable
+    public LauncherActivityInfo getAppLaunchInfo(@Nullable final String pkg,
+            @NonNull final UserHandle user) {
         List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
-        return activities.isEmpty() ? null :
-                AppInfo.makeLaunchIntent(activities.get(0));
+        return activities.isEmpty() ? null : activities.get(0);
     }
 
     /**
@@ -170,10 +194,11 @@
     /**
      * Starts the details activity for {@code info}
      */
-    public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
+    public static void startDetailsActivityForInfo(Context context, ItemInfo info,
+            Rect sourceBounds, Bundle opts) {
         if (info instanceof ItemInfoWithIcon appInfo
                 && (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
-            mContext.startActivity(ApiWrapper.INSTANCE.get(mContext).getAppMarketActivityIntent(
+            context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
                     appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()));
             return;
         }
@@ -189,9 +214,10 @@
         }
         if (componentName != null) {
             try {
-                mLauncherApps.startAppDetailsActivity(componentName, info.user, sourceBounds, opts);
+                context.getSystemService(LauncherApps.class).startAppDetailsActivity(componentName,
+                        info.user, sourceBounds, opts);
             } catch (SecurityException | ActivityNotFoundException e) {
-                Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+                Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                 Log.e(TAG, "Unable to launch settings", e);
             }
         }
@@ -276,4 +302,47 @@
         return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || (
                 Flags.enableSupportForArchiving() && info.isArchived);
     }
+
+    /**
+     * Returns whether the given component or its application has the multi-instance property set.
+     */
+    public boolean supportsMultiInstance(@NonNull ComponentName component) {
+        // Check the legacy hardcoded allowlist first
+        for (String pkg : mLegacyMultiInstanceSupportedApps) {
+            if (pkg.equals(component.getPackageName())) {
+                return true;
+            }
+        }
+
+        // Check app multi-instance properties after V
+        if (!Utilities.ATLEAST_V) {
+            return false;
+        }
+
+        try {
+            // Check if the component has the multi-instance property
+            return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI, component)
+                    .getBoolean();
+        } catch (PackageManager.NameNotFoundException e1) {
+            try {
+                // Check if the application has the multi-instance property
+                return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI,
+                                component.getPackageName())
+                    .getBoolean();
+            } catch (PackageManager.NameNotFoundException e2) {
+                // Fall through
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether two apps should be considered the same for multi-instance purposes, which
+     * requires additional checks to ensure they can be started as multiple instances.
+     */
+    public static boolean isSameAppForMultiInstance(@NonNull ItemInfo app1,
+            @NonNull ItemInfo app2) {
+        return app1.getTargetPackage().equals(app2.getTargetPackage())
+                && app1.user.equals(app2.user);
+    }
 }
diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java
index 67530a6..e16e477 100644
--- a/src/com/android/launcher3/util/ScreenOnTracker.java
+++ b/src/com/android/launcher3/util/ScreenOnTracker.java
@@ -27,7 +27,7 @@
 /**
  * Utility class for tracking if the screen is currently on or off
  */
-public class ScreenOnTracker {
+public class ScreenOnTracker implements SafeCloseable {
 
     public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
             new MainThreadInitializedObject<>(ScreenOnTracker::new);
@@ -35,14 +35,21 @@
     private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
     private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
 
+    private final Context mContext;
     private boolean mIsScreenOn;
 
     private ScreenOnTracker(Context context) {
         // Assume that the screen is on to begin with
+        mContext = context;
         mIsScreenOn = true;
         mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
     }
 
+    @Override
+    public void close() {
+        mReceiver.unregisterReceiverSafely(mContext);
+    }
+
     private void onReceive(Intent intent) {
         String action = intent.getAction();
         if (ACTION_SCREEN_ON.equals(action)) {
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index cd60c1d..51749a7 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -19,14 +19,12 @@
 import static android.os.VibrationEffect.createPredefined;
 import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
 
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import android.annotation.SuppressLint;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.database.ContentObserver;
 import android.media.AudioAttributes;
+import android.net.Uri;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -39,7 +37,7 @@
 /**
  * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
  */
-public class VibratorWrapper {
+public class VibratorWrapper implements SafeCloseable {
 
     public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
             new MainThreadInitializedObject<>(VibratorWrapper::new);
@@ -51,6 +49,8 @@
 
     public static final VibrationEffect EFFECT_CLICK =
             createPredefined(VibrationEffect.EFFECT_CLICK);
+    private static final Uri HAPTIC_FEEDBACK_URI =
+            Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
 
     private static final float LOW_TICK_SCALE = 0.9f;
     private static final float DRAG_TEXTURE_SCALE = 0.03f;
@@ -76,6 +76,8 @@
     private final Context mContext;
     private final Vibrator mVibrator;
     private final boolean mHasVibrator;
+    private final SettingsCache.OnChangeListener mHapticChangeListener =
+            isEnabled -> mIsHapticFeedbackEnabled = isEnabled;
 
     private boolean mIsHapticFeedbackEnabled;
 
@@ -84,16 +86,9 @@
         mVibrator = context.getSystemService(Vibrator.class);
         mHasVibrator = mVibrator.hasVibrator();
         if (mHasVibrator) {
-            final ContentResolver resolver = context.getContentResolver();
-            mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
-            final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
-                }
-            };
-            resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
-                    false /* notifyForDescendants */, observer);
+            SettingsCache cache = SettingsCache.INSTANCE.get(mContext);
+            cache.register(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+            mIsHapticFeedbackEnabled = cache.getValue(HAPTIC_FEEDBACK_URI, 0);
         } else {
             mIsHapticFeedbackEnabled = false;
         }
@@ -126,6 +121,14 @@
         }
     }
 
+    @Override
+    public void close() {
+        if (mHasVibrator) {
+            SettingsCache.INSTANCE.get(mContext)
+                    .unregister(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+        }
+    }
+
     /**
      * This is called when the user swipes to/from all apps. This is meant to be used in between
      * long animation progresses so that it gives a dragging texture effect. For a better
@@ -175,10 +178,6 @@
         mLastDragTime = 0;
     }
 
-    private boolean isHapticFeedbackEnabled(ContentResolver resolver) {
-        return Settings.System.getInt(resolver, HAPTIC_FEEDBACK_ENABLED, 0) == 1;
-    }
-
     /** Vibrates with the given effect if haptic feedback is available and enabled. */
     public void vibrate(VibrationEffect vibrationEffect) {
         if (mHasVibrator && mIsHapticFeedbackEnabled) {
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 998191e..0817c0a 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.WindowBounds;
 
 import java.util.ArrayList;
@@ -67,7 +68,7 @@
 /**
  * Utility class for mocking some window manager behaviours
  */
-public class WindowManagerProxy implements ResourceBasedOverride {
+public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
 
     private static final String TAG = "WindowManagerProxy";
     public static final int MIN_TABLET_WIDTH = 600;
@@ -114,6 +115,13 @@
     }
 
     /**
+     * Returns if we are in desktop mode or not.
+     */
+    public boolean isInDesktopMode() {
+        return false;
+    }
+
+    /**
      * Returns the real bounds for the provided display after applying any insets normalization
      */
     public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
@@ -305,12 +313,12 @@
 
         navBarHeightPortrait = isTablet
                 ? (mTaskbarDrawnInProcess
-                        ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+                        ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
                 : getDimenByName(systemRes, NAVBAR_HEIGHT);
 
         navBarHeightLandscape = isTablet
                 ? (mTaskbarDrawnInProcess
-                        ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+                        ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
                 : (isTabletOrGesture
                         ? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
         navbarWidthLandscape = isTabletOrGesture
@@ -474,6 +482,9 @@
                 NavigationMode.THREE_BUTTONS;
     }
 
+    @Override
+    public void close() { }
+
     /**
      * @see DisplayCutout#getSafeInsets
      */
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 9f6e8f8..5ce455a 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -25,6 +25,8 @@
 import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS;
 import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -135,6 +137,7 @@
     protected final AnimatedFloat mSwipeToDismissProgress =
             new AnimatedFloat(this::onUserSwipeToDismissProgressChanged, 0f);
     protected boolean mIsDismissInProgress;
+    private View mViewToAnimateInSwipeToDismiss = this;
     private @Nullable Drawable mContentBackground;
     private @Nullable View mContentBackgroundParentView;
 
@@ -286,18 +289,37 @@
 
     @Override
     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public void onBackStarted(BackEvent backEvent) {
+        super.onBackStarted(backEvent);
+        mViewToAnimateInSwipeToDismiss = shouldAnimateContentViewInBackSwipe() ? mContent : this;
+    }
+
+    @Override
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     public void onBackProgressed(BackEvent backEvent) {
         final float progress = backEvent.getProgress();
         float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(progress);
         mSwipeToDismissProgress.updateValue(deceleratedProgress);
     }
 
+    /**
+     * During predictive back swipe, the default behavior is to scale {@link AbstractSlideInView}
+     * during back swipe. This method allow subclass to scale {@link #mContent}, typically to exit
+     * search mode.
+     *
+     * <p>Note that this method can be expensive, and should only be called from
+     * {@link #onBackStarted(BackEvent)}, not from {@link #onBackProgressed(BackEvent)}.
+     */
+    protected boolean shouldAnimateContentViewInBackSwipe() {
+        return false;
+    }
+
     protected void onUserSwipeToDismissProgressChanged() {
         float progress = mSwipeToDismissProgress.value;
         mIsDismissInProgress = progress > 0f;
 
         float scale = PREDICTIVE_BACK_MIN_SCALE + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1f - progress);
-        SCALE_PROPERTY.set(this, scale);
+        SCALE_PROPERTY.set(mViewToAnimateInSwipeToDismiss, scale);
         setClipChildren(!mIsDismissInProgress);
         setClipToPadding(!mIsDismissInProgress);
         mContent.setClipChildren(!mIsDismissInProgress);
@@ -312,9 +334,32 @@
     }
 
     protected void animateSwipeToDismissProgressToStart() {
-        mSwipeToDismissProgress.animateToValue(0f)
-                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
-                .start();
+        ObjectAnimator objectAnimator = mSwipeToDismissProgress.animateToValue(0f)
+                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS);
+
+        // If we are animating a different view, we should reset the animating view back to
+        // AbstractSlideInView as it is the default view to animate.
+        if (this != mViewToAnimateInSwipeToDismiss) {
+            objectAnimator.addListener(new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationCancel(Animator animator) {
+                    mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animator) {}
+
+                @Override
+                public void onAnimationStart(Animator animator) {}
+            });
+        }
+
+        objectAnimator.start();
     }
 
     @Override
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index bf43a22..cfac91a 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -41,6 +41,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -515,10 +516,21 @@
     static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
         if (context instanceof ActivityContext) {
             return (T) context;
+        } else if (context instanceof ActivityContextDelegate acd) {
+            return (T) acd.mDelegate;
         } else if (context instanceof ContextWrapper) {
             return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
         } else {
             return null;
         }
     }
+
+    class ActivityContextDelegate extends ContextThemeWrapper {
+        public final ActivityContext mDelegate;
+
+        public ActivityContextDelegate(Context base, int themeResId, ActivityContext delegate) {
+            super(base, themeResId);
+            mDelegate = delegate;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
index 2f0da03..bb4f040 100644
--- a/src/com/android/launcher3/views/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -54,7 +54,7 @@
  */
 public class ArrowTipView extends AbstractFloatingView {
 
-    private static final String TAG = ArrowTipView.class.getSimpleName();
+    private static final String TAG = "ArrowTipView";
     private static final long AUTO_CLOSE_TIMEOUT_MILLIS = 10 * 1000;
     private static final long SHOW_DELAY_MS = 200;
     private static final long SHOW_DURATION_MS = 300;
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 5d3fa9b..325c1cd 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -18,12 +18,11 @@
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.Utilities.boundToRange;
 import static com.android.launcher3.Utilities.mapToRange;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 
 import static java.lang.Math.max;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -41,6 +40,7 @@
 import android.view.ViewOutlineProvider;
 
 import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
@@ -75,6 +75,8 @@
     private final Rect mOutline = new Rect();
     private final Rect mFinalDrawableBounds = new Rect();
 
+    @Nullable private TaskViewArtist mTaskViewArtist;
+
     public ClipIconView(Context context) {
         this(context, null);
     }
@@ -91,10 +93,28 @@
     }
 
     /**
+     * Sets a {@link TaskViewArtist} that will draw a {@link com.android.quickstep.views.TaskView}
+     * within the clip bounds of this view.
+     */
+    public void setTaskViewArtist(TaskViewArtist taskViewArtist) {
+        mTaskViewArtist = taskViewArtist;
+        invalidate();
+    }
+
+    /**
      * Update the icon UI to match the provided parameters during an animation frame
      */
     public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
             boolean isOpening, View container, DeviceProfile dp) {
+        update(rect, progress, shapeProgressStart, cornerRadius, isOpening, container, dp, 255);
+    }
+
+    /**
+     * Update the icon UI to match the provided parameters during an animation frame, optionally
+     * varying the alpha of the {@link TaskViewArtist}
+     */
+    public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
+            boolean isOpening, View container, DeviceProfile dp, int taskViewDrawAlpha) {
         MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
 
         float dX = mIsRtl
@@ -108,6 +128,14 @@
         float scaleX = rect.width() / minSize;
         float scaleY = rect.height() / minSize;
         float scale = Math.max(1f, Math.min(scaleX, scaleY));
+        if (mTaskViewArtist != null) {
+            mTaskViewArtist.taskViewDrawWidth = lp.width;
+            mTaskViewArtist.taskViewDrawHeight = lp.height;
+            mTaskViewArtist.taskViewDrawAlpha = taskViewDrawAlpha;
+            mTaskViewArtist.taskViewDrawScale = (mTaskViewArtist.drawForPortraitLayout
+                    ? Math.min(lp.height, lp.width) : Math.max(lp.height, lp.width))
+                    / mTaskViewArtist.taskViewMinSize;
+        }
 
         if (Float.isNaN(scale) || Float.isInfinite(scale)) {
             // Views are no longer laid out, do not update.
@@ -142,14 +170,10 @@
         if (mIsAdaptiveIcon) {
             if (!isOpening && progress >= shapeProgressStart) {
                 if (mRevealAnimator == null) {
-                    mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(
-                            this, mStartRevealRect, mOutline, mTaskCornerRadius, !isOpening);
-                    mRevealAnimator.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mRevealAnimator = null;
-                        }
-                    });
+                    mRevealAnimator = IconShape.INSTANCE.get(getContext()).getShape()
+                            .createRevealAnimator(this, mStartRevealRect,
+                                    mOutline, mTaskCornerRadius, !isOpening);
+                    mRevealAnimator.addListener(forEndCallback(() -> mRevealAnimator = null));
                     mRevealAnimator.start();
                     // We pause here so we can set the current fraction ourselves.
                     mRevealAnimator.pause();
@@ -230,7 +254,8 @@
             mStartRevealRect.set(0, 0, originalWidth, originalHeight);
 
             if (!isFolderIcon) {
-                Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
+                Utilities.scaleRectAboutCenter(mStartRevealRect,
+                        IconShape.INSTANCE.get(getContext()).getNormalizationScale());
             }
 
             if (dp.isLandscape) {
@@ -291,6 +316,19 @@
         if (mForeground != null) {
             mForeground.draw(canvas);
         }
+        if (mTaskViewArtist != null) {
+            canvas.saveLayerAlpha(
+                    0,
+                    0,
+                    mTaskViewArtist.taskViewDrawWidth,
+                    mTaskViewArtist.taskViewDrawHeight,
+                    mTaskViewArtist.taskViewDrawAlpha);
+            float drawScale = mTaskViewArtist.taskViewDrawScale;
+            canvas.translate(drawScale * mTaskViewArtist.taskViewTranslationX,
+                    drawScale * mTaskViewArtist.taskViewTranslationY);
+            canvas.scale(drawScale, drawScale);
+            mTaskViewArtist.taskViewDrawCallback.accept(canvas);
+        }
         canvas.restoreToCount(count);
     }
 
@@ -307,5 +345,37 @@
         mRevealAnimator = null;
         mTaskCornerRadius = 0;
         mOutline.setEmpty();
+        mTaskViewArtist = null;
+    }
+
+    /**
+     * Utility class to help draw a {@link com.android.quickstep.views.TaskView} within
+     * a {@link ClipIconView} bounds.
+     */
+    public static class TaskViewArtist {
+
+        public final Consumer<Canvas> taskViewDrawCallback;
+        public final float taskViewTranslationX;
+        public final float taskViewTranslationY;
+        public final float taskViewMinSize;
+        public final boolean drawForPortraitLayout;
+
+        public int taskViewDrawAlpha;
+        public float taskViewDrawScale;
+        public int taskViewDrawWidth;
+        public int taskViewDrawHeight;
+
+        public TaskViewArtist(
+                Consumer<Canvas> taskViewDrawCallback,
+                float taskViewTranslationX,
+                float taskViewTranslationY,
+                float taskViewMinSize,
+                boolean drawForPortraitLayout) {
+            this.taskViewDrawCallback = taskViewDrawCallback;
+            this.taskViewTranslationX = taskViewTranslationX;
+            this.taskViewTranslationY = taskViewTranslationY;
+            this.taskViewMinSize = taskViewMinSize;
+            this.drawForPortraitLayout = drawForPortraitLayout;
+        }
     }
 }
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index a309e6e..bc66a33 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -77,6 +77,7 @@
         canvas.restore();
 
         drawDotIfNecessary(canvas);
+        drawRunningAppIndicatorIfNecessary(canvas);
     }
 
     public static class ShadowInfo {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index f76b53b..1d5a9dc 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -68,7 +68,7 @@
 public class FloatingIconView extends FrameLayout implements
         Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView {
 
-    private static final String TAG = FloatingIconView.class.getSimpleName();
+    private static final String TAG = "FloatingIconView";
 
     // Manages loading the icon on a worker thread
     private static @Nullable IconLoadResult sIconLoadResult;
@@ -145,18 +145,28 @@
     }
 
     /**
-     * Positions this view to match the size and location of {@param rect}.
-     * @param alpha The alpha[0, 1] of the entire floating view.
-     * @param progress A value from [0, 1] that represents the animation progress.
-     * @param shapeProgressStart The progress value at which to start the shape reveal.
-     * @param cornerRadius The corner radius of {@param rect}.
-     * @param isOpening True if view is used for app open animation, false for app close animation.
+     * Positions this view to match the size and location of {@code rect}.
      */
     public void update(float alpha, RectF rect, float progress, float shapeProgressStart,
             float cornerRadius, boolean isOpening) {
-        setAlpha(alpha);
+        update(alpha, rect, progress, shapeProgressStart, cornerRadius, isOpening, 0);
+    }
+
+    /**
+     * Positions this view to match the size and location of {@code rect}.
+     * <p>
+     * @param alpha The alpha[0, 1] of the entire floating view.
+     * @param progress A value from [0, 1] that represents the animation progress.
+     * @param shapeProgressStart The progress value at which to start the shape reveal.
+     * @param cornerRadius The corner radius of {@code rect}.
+     * @param isOpening True if view is used for app open animation, false for app close animation.
+     * @param taskViewDrawAlpha the drawn {@link com.android.quickstep.views.TaskView} alpha
+     */
+    public void update(float alpha, RectF rect, float progress, float shapeProgressStart,
+            float cornerRadius, boolean isOpening, int taskViewDrawAlpha) {
+        setAlpha(isLaidOut() ? alpha : 0f);
         mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, this,
-                mLauncher.getDeviceProfile());
+                mLauncher.getDeviceProfile(), taskViewDrawAlpha);
 
         if (mFadeOutView != null) {
             // The alpha goes from 1 to 0 when progress is 0 and 0.33 respectively.
@@ -164,6 +174,14 @@
         }
     }
 
+    /**
+     * Sets a {@link com.android.quickstep.views.TaskView} that will draw a
+     * {@link com.android.quickstep.views.TaskView} within the {@code mClipIconView} clip bounds
+     */
+    public void setOverlayArtist(ClipIconView.TaskViewArtist taskViewArtist) {
+        mClipIconView.setTaskViewArtist(taskViewArtist);
+    }
+
     @Override
     public void onAnimationEnd(Animator animator) {
         if (mLoadIconSignal != null) {
@@ -178,8 +196,8 @@
     }
 
     /**
-     * Sets the size and position of this view to match {@param v}.
-     *
+     * Sets the size and position of this view to match {@code v}.
+     * <p>
      * @param v The view to copy
      * @param positionOut Rect that will hold the size and position of v.
      */
@@ -253,10 +271,11 @@
 
     /**
      * Loads the icon and saves the results to {@link #sIconLoadResult}.
+     * <p>
      * Runs onIconLoaded callback (if any), which signifies that the FloatingIconView is
      * ready to display the icon. Otherwise, the FloatingIconView will grab the results when its
      * initialized.
-     *
+     * <p>
      * @param originalView The View that the FloatingIconView will replace.
      * @param info ItemInfo of the originalView
      * @param pos The position of the view.
@@ -282,6 +301,8 @@
         } else if (btvIcon instanceof PreloadIconDrawable) {
             // Force the progress bar to display.
             drawable = btvIcon;
+        } else if (originalView instanceof ImageView) {
+            drawable = ((ImageView) originalView).getDrawable();
         } else {
             int width = (int) pos.width();
             int height = (int) pos.height();
@@ -321,8 +342,8 @@
     }
 
     /**
-     * Sets the drawables of the {@param originalView} onto this view.
-     *
+     * Sets the drawables of the {@code originalView} onto this view.
+     * <p>
      * @param drawable The drawable of the original view.
      * @param badge The badge of the original view.
      * @param iconOffset The amount of offset needed to match this view with the original view.
@@ -365,11 +386,11 @@
 
     /**
      * Draws the drawable of the BubbleTextView behind ClipIconView
-     *
+     * <p>
      * This is used to:
      * - Have icon displayed while Adaptive Icon is loading
      * - Displays the built in shadow to ensure a clean handoff
-     *
+     * <p>
      * Allows nullable as this may be cleared when drawing is deferred to ClipIconView.
      */
     private void setOriginalDrawableBackground(@Nullable Supplier<Drawable> btvIcon) {
@@ -570,11 +591,12 @@
     }
 
     /**
-     * Creates a floating icon view for {@param originalView}.
+     * Creates a floating icon view for {@code originalView}.
+     * <p>
      * @param originalView The view to copy
      * @param visibilitySyncView A view whose visibility should update in sync with originalView.
      * @param fadeOutView A view that will fade out as the animation progresses.
-     * @param hideOriginal If true, it will hide {@param originalView} while this view is visible.
+     * @param hideOriginal If true, it will hide {@code originalView} while this view is visible.
      *                     Else, we will not draw anything in this view.
      * @param positionOut Rect that will hold the size and position of v.
      * @param isOpening True if this view replaces the icon for app open animation.
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 8408cc7..df8f635 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -30,6 +30,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Property;
@@ -121,7 +122,7 @@
     // Fast scroller popup
     private TextView mPopupView;
     private boolean mPopupVisible;
-    private String mPopupSectionName;
+    private CharSequence mPopupSectionName;
     private Insets mSystemGestureInsets;
 
     protected FastScrollRecyclerView mRv;
@@ -307,13 +308,13 @@
         // Update the fastscroller section name at this touch position
         int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
         float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
-        String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
+        CharSequence sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
         if (!sectionName.equals(mPopupSectionName)) {
             mPopupSectionName = sectionName;
             mPopupView.setText(sectionName);
             performHapticFeedback(CLOCK_TICK);
         }
-        animatePopupVisibility(!sectionName.isEmpty());
+        animatePopupVisibility(!TextUtils.isEmpty(sectionName));
         mLastTouchY = boundedY;
         setThumbOffsetY((int) mLastTouchY);
     }
diff --git a/src/com/android/launcher3/views/StickyHeaderLayout.java b/src/com/android/launcher3/views/StickyHeaderLayout.java
index d6481a9..090251f 100644
--- a/src/com/android/launcher3/views/StickyHeaderLayout.java
+++ b/src/com/android/launcher3/views/StickyHeaderLayout.java
@@ -36,6 +36,9 @@
 
 import com.android.launcher3.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A {@link LinearLayout} container which allows scrolling parts of its content based on the
  * scroll of a different view. Views which are marked as sticky are not scrolled, giving the
@@ -242,6 +245,22 @@
         return p instanceof MyLayoutParams;
     }
 
+    /**
+     * Return a list of all the children that have the sticky layout param set.
+     */
+    public List<View> getStickyChildren() {
+        List<View> stickyChildren = new ArrayList<>();
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View v = getChildAt(i);
+            MyLayoutParams lp = (MyLayoutParams) v.getLayoutParams();
+            if (lp.sticky) {
+                stickyChildren.add(v);
+            }
+        }
+        return stickyChildren;
+    }
+
     private static class MyLayoutParams extends LayoutParams {
 
         public final boolean sticky;
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
deleted file mode 100644
index 53fbd8f..0000000
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.R;
-
-/**
- * Education view about widgets.
- */
-public class WidgetsEduView extends AbstractSlideInView<BaseActivity> implements Insettable {
-
-    private static final int DEFAULT_CLOSE_DURATION = 200;
-
-    private Rect mInsets = new Rect();
-
-    public WidgetsEduView(Context context, AttributeSet attr) {
-        this(context, attr, 0);
-    }
-
-    public WidgetsEduView(Context context, AttributeSet attrs,
-            int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    protected void handleClose(boolean animate) {
-        handleClose(true, DEFAULT_CLOSE_DURATION);
-    }
-
-    @Override
-    protected boolean isOfType(int type) {
-        return (type & TYPE_WIDGETS_EDUCATION_DIALOG) != 0;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mContent = findViewById(R.id.edu_view);
-        findViewById(R.id.edu_close_button)
-                .setOnClickListener(v -> close(/* animate= */ true));
-        setContentBackgroundWithParent(mContent.getBackground(), mContent);
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        mContent.setPadding(mContent.getPaddingStart(),
-                mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
-    }
-
-    @Override
-    protected void onUserSwipeToDismissProgressChanged() {
-        super.onUserSwipeToDismissProgressChanged();
-        setTranslationY(getMeasuredHeight() * (mSwipeToDismissProgress.value / 2));
-    }
-
-    private void show() {
-        attachToContainer();
-        animateOpen();
-    }
-
-    @Override
-    protected int getScrimColor(Context context) {
-        return context.getResources().getColor(R.color.widgets_picker_scrim);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int width = r - l;
-        int height = b - t;
-
-        // Lay out the content as center bottom aligned.
-        int contentWidth = mContent.getMeasuredWidth();
-        int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
-        mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
-                contentLeft + contentWidth, height);
-
-        setTranslationShift(mTranslationShift);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
-        int widthUsed;
-        if (mInsets.bottom > 0) {
-            // Extra space between this view and mContent horizontally when the sheet is shown in
-            // portrait mode.
-            widthUsed = mInsets.left + mInsets.right;
-        } else {
-            // Extra space between this view and mContent horizontally when the sheet is shown in
-            // landscape mode.
-            Rect padding = deviceProfile.workspacePadding;
-            widthUsed = Math.max(padding.left + padding.right,
-                    2 * (mInsets.left + mInsets.right));
-        }
-
-        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, heightUsed);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
-    }
-
-    private void animateOpen() {
-        if (mIsOpen || mOpenCloseAnimation.getAnimationPlayer().isRunning()) {
-            return;
-        }
-        mIsOpen = true;
-        setUpDefaultOpenAnimation().start();
-    }
-
-    /** Shows widget education dialog. */
-    public static WidgetsEduView showEducationDialog(BaseActivity activity) {
-        LayoutInflater layoutInflater = LayoutInflater.from(activity);
-        WidgetsEduView v = (WidgetsEduView) layoutInflater.inflate(
-                R.layout.widgets_edu, activity.getDragLayer(), false);
-        v.show();
-        return v;
-    }
-}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index c17ae09..1368084 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,10 +16,9 @@
 package com.android.launcher3.widget;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
-import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
 import static com.android.launcher3.Flags.enableWidgetTapToAdd;
-import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
 
 import android.content.Context;
@@ -27,6 +26,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
@@ -36,17 +36,15 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
-import androidx.core.view.ViewCompat;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -54,7 +52,6 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.launcher3.views.AbstractSlideInView;
-import com.android.launcher3.views.ArrowTipView;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -80,6 +77,7 @@
     private boolean mDisableNavBarScrim = false;
 
     @Nullable private WidgetCell mWidgetCellWithAddButton = null;
+    @Nullable private WidgetItem mLastSelectedWidgetItem = null;
 
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -141,9 +139,18 @@
         }
 
         if (enableWidgetTapToAdd()) {
+            scrollToWidgetCell(wc);
+
             if (mWidgetCellWithAddButton != null) {
-                // If there is a add button currently showing, hide it.
-                mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+                if (mWidgetCellWithAddButton.isShowingAddButton()) {
+                    // If there is a add button currently showing, hide it.
+                    mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+                } else {
+                    // The last recorded widget cell to show an add button is no longer showing it,
+                    // likely because the widget cell has been recycled or lost focus. If this is
+                    // the cell that has been clicked, we will show it below.
+                    mWidgetCellWithAddButton = null;
+                }
             }
 
             if (mWidgetCellWithAddButton != wc) {
@@ -158,13 +165,26 @@
             }
 
             mWidgetCellWithAddButton = mWidgetCellWithAddButton != wc ? wc : null;
+            if (mWidgetCellWithAddButton != null) {
+                mLastSelectedWidgetItem = mWidgetCellWithAddButton.getWidgetItem();
+            } else {
+                mLastSelectedWidgetItem = null;
+            }
         } else {
             mActivityContext.getItemOnClickListener().onClick(wc);
         }
     }
 
+    @Override
+    protected float getShiftRange() {
+        // We add the extra height added during predictive back / swipe up to the shift range, so
+        // that the idle interpolator knows to animate the view off fully.
+        return mContent.getHeight() + getBottomOffsetPx();
+    }
+
     /**
-     * Click handler for tap to add button.
+     * Click handler for tap to add button. This handler assumes we are in the Launcher activity and
+     * should not be used when the widget sheet is displayed elsewhere.
      */
     private void addWidget(@NonNull PendingAddItemInfo info) {
         // Using a boolean flag here to make sure the callback is only run once. This should never
@@ -172,19 +192,77 @@
         // needed.
         final AtomicBoolean hasRun = new AtomicBoolean(false);
         addOnCloseListener(() -> {
-            if (!hasRun.get()) {
-                Launcher.getLauncher(mActivityContext).getAccessibilityDelegate().addToWorkspace(
-                        info, /*accessibility=*/ false,
+            if (hasRun.get()) return;
+            hasRun.set(true);
+
+            // Going to NORMAL state will also dismiss the All Apps view if it is showing.
+            Launcher launcher = Launcher.getLauncher(mActivityContext);
+            launcher.getStateManager().goToState(NORMAL, forSuccessCallback(() -> {
+                launcher.getAccessibilityDelegate().addToWorkspace(info,
+                        /*accessibility=*/ false,
                         /*finishCallback=*/ (success) -> {
                             mActivityContext.getStatsLogManager()
                                     .logger()
                                     .withItemInfo(info)
                                     .log(LAUNCHER_WIDGET_ADD_BUTTON_TAP);
                         });
-                hasRun.set(true);
-            }
+            }));
         });
-        handleClose(true);
+        close(/* animate= */ true);
+    }
+
+    /**
+     * Scroll to show the widget cell. If both the bottom and top of the cell are clipped, this will
+     * prioritize showing the bottom of the cell (where the add button is).
+     */
+    private void scrollToWidgetCell(@NonNull WidgetCell wc) {
+        final int headerTopClip = getHeaderTopClip(wc);
+        final Rect visibleRect = new Rect();
+        final boolean isPartiallyVisible = wc.getLocalVisibleRect(visibleRect);
+        int scrollByY = 0;
+        if (isPartiallyVisible) {
+            final int scrollPadding = getResources()
+                    .getDimensionPixelSize(R.dimen.widget_cell_add_button_scroll_padding);
+            final int topClip = visibleRect.top + headerTopClip;
+            final int bottomClip = wc.getHeight() - visibleRect.bottom;
+            if (bottomClip != 0) {
+                scrollByY = bottomClip + scrollPadding;
+            } else if (topClip != 0) {
+                scrollByY = -topClip - scrollPadding;
+            }
+        }
+
+        if (isPartiallyVisible && scrollByY == 0) {
+            // Widget is fully visible.
+            return;
+        } else if (!isPartiallyVisible) {
+            Log.e("BaseWidgetSheet", "click on invisible WidgetCell should not be possible");
+            return;
+        }
+
+        scrollCellContainerByY(wc, scrollByY);
+    }
+
+    /**
+     * Find the nearest scrollable container of the given WidgetCell, and scroll by the given
+     * amount.
+     */
+    protected abstract void scrollCellContainerByY(WidgetCell wc, int scrollByY);
+
+
+    /**
+     * Return the top clip of any sticky headers over the given cell.
+     */
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        return 0;
+    }
+
+    /**
+     * Returns the component of the widget that is currently showing an add button, if any.
+     */
+    @Nullable
+    protected WidgetItem getLastSelectedWidgetItem() {
+        return mLastSelectedWidgetItem;
     }
 
     @Override
@@ -272,19 +350,8 @@
                 MeasureSpec.getSize(heightMeasureSpec));
     }
 
-    private int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
-        // All bottom-sheets showing widgets will be full-width across all devices.
-        if (enableCategorizedWidgetSuggestions()) {
-            return 0;
-        }
-        if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
-            return getResources().getDimensionPixelSize(
-                    R.dimen.widget_picker_landscape_tablet_left_right_margin);
-        }
-        if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
-            return getResources().getDimensionPixelSize(
-                    R.dimen.widget_picker_two_panels_left_right_margin);
-        }
+    /** Returns the horizontal margins to be applied to the widget sheet. **/
+    protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
         return deviceProfile.allAppsLeftRightMargin;
     }
 
@@ -323,31 +390,6 @@
         return mActivityContext.getSystemUiController();
     }
 
-    /** Shows education tip on top center of {@code view} if view is laid out. */
-    @Nullable
-    protected ArrowTipView showEducationTipOnViewIfPossible(@Nullable View view) {
-        if (view == null || !ViewCompat.isLaidOut(view)) {
-            return null;
-        }
-        int[] coords = new int[2];
-        view.getLocationOnScreen(coords);
-        ArrowTipView arrowTipView =
-                new ArrowTipView(mActivityContext,  /* isPointingUp= */ false).showAtLocation(
-                        getContext().getString(R.string.long_press_widget_to_add),
-                        /* arrowXCoord= */coords[0] + view.getWidth() / 2,
-                        /* yCoord= */coords[1]);
-        if (arrowTipView != null) {
-            LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_TIP_SEEN, true);
-        }
-        return arrowTipView;
-    }
-
-    /** Returns {@code true} if tip has previously been shown on any of {@link BaseWidgetSheet}. */
-    protected boolean hasSeenEducationTip() {
-        return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_TIP_SEEN)
-                || Utilities.isRunningInTestHarness();
-    }
-
     @Override
     protected void setTranslationShift(float translationShift) {
         super.setTranslationShift(translationShift);
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index c3e9ad6..44ab966 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
@@ -52,8 +51,7 @@
  * {@inheritDoc}
  */
 public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
-        implements TouchCompleteListener, View.OnLongClickListener,
-        LocalColorExtractor.Listener {
+        implements TouchCompleteListener, View.OnLongClickListener {
 
     private static final String TAG = "LauncherAppWidgetHostView";
 
@@ -70,13 +68,9 @@
 
     private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
 
-    private final Rect mTempRect = new Rect();
     private final CheckLongPressHelper mLongPressHelper;
     protected final ActivityContext mActivityContext;
 
-    // Maintain the color manager.
-    private final LocalColorExtractor mColorExtractor;
-
     private boolean mIsScrollable;
     private boolean mIsAttachedToWindow;
     private boolean mIsAutoAdvanceRegistered;
@@ -84,11 +78,6 @@
 
     private long mDeferUpdatesUntilMillis = 0;
     RemoteViews mLastRemoteViews;
-    private boolean mHasDeferredColorChange = false;
-    private @Nullable SparseIntArray mDeferredColorChange = null;
-
-    // The following member variables are only used during drag-n-drop.
-    private boolean mIsInDragMode = false;
 
     private boolean mTrackingWidgetUpdate = false;
 
@@ -109,7 +98,6 @@
         if (Themes.getAttrBoolean(context, R.attr.isWorkspaceDarkText)) {
             setOnLightBackground(true);
         }
-        mColorExtractor = new LocalColorExtractor(); // no-op
     }
 
     @Override
@@ -177,8 +165,8 @@
     }
 
     /**
-     * Returns true if the application of {@link RemoteViews} through {@link #updateAppWidget} and
-     * colors through {@link #onColorsChanged} are currently being deferred.
+     * Returns true if the application of {@link RemoteViews} through {@link #updateAppWidget} are
+     * currently being deferred.
      * @see #beginDeferringUpdates()
      */
     private boolean isDeferringUpdates() {
@@ -187,9 +175,8 @@
 
     /**
      * Begin deferring the application of any {@link RemoteViews} updates made through
-     * {@link #updateAppWidget} and color changes through {@link #onColorsChanged} until
-     * {@link #endDeferringUpdates()} has been called or the next {@link #updateAppWidget} or
-     * {@link #onColorsChanged} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS} have elapsed.
+     * {@link #updateAppWidget} until {@link #endDeferringUpdates()} has been called or the next
+     * {@link #updateAppWidget} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS} have elapsed.
      */
     public void beginDeferringUpdates() {
         mDeferUpdatesUntilMillis = SystemClock.uptimeMillis() + UPDATE_LOCK_TIMEOUT_MILLIS;
@@ -197,26 +184,16 @@
 
     /**
      * Stop deferring the application of {@link RemoteViews} updates made through
-     * {@link #updateAppWidget} and color changes made through {@link #onColorsChanged} and apply
-     * any deferred updates.
+     * {@link #updateAppWidget} and apply any deferred updates.
      */
     public void endDeferringUpdates() {
         RemoteViews remoteViews;
-        SparseIntArray deferredColors;
-        boolean hasDeferredColors;
         mDeferUpdatesUntilMillis = 0;
         remoteViews = mLastRemoteViews;
-        deferredColors = mDeferredColorChange;
-        hasDeferredColors = mHasDeferredColorChange;
-        mDeferredColorChange = null;
-        mHasDeferredColorChange = false;
 
         if (remoteViews != null) {
             updateAppWidget(remoteViews);
         }
-        if (hasDeferredColors) {
-            onColorsChanged(deferredColors);
-        }
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -242,7 +219,6 @@
         super.onAttachedToWindow();
         mIsAttachedToWindow = true;
         checkIfAutoAdvance();
-        mColorExtractor.setListener(this);
     }
 
     @Override
@@ -253,7 +229,6 @@
         // state is updated. So isAttachedToWindow() will return true until next frame.
         mIsAttachedToWindow = false;
         checkIfAutoAdvance();
-        mColorExtractor.setListener(null);
     }
 
     @Override
@@ -292,29 +267,6 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         mIsScrollable = checkScrollableRecursively(this);
-
-        if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo info) {
-            mTempRect.set(left, top, right, bottom);
-            mColorExtractor.setWorkspaceLocation(mTempRect, (View) getParent(), info.screenId);
-        }
-    }
-
-    /** Starts the drag mode. */
-    public void startDrag() {
-        mIsInDragMode = true;
-    }
-
-    /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */
-    public void handleDrag(Rect rectInView, View view, int screenId) {
-        if (mIsInDragMode) {
-            mColorExtractor.setWorkspaceLocation(rectInView, view, screenId);
-        }
-    }
-
-    /** Ends the drag mode. */
-    public void endDrag() {
-        mIsInDragMode = false;
-        requestLayout();
     }
 
     /**
@@ -338,20 +290,6 @@
     }
 
     @Override
-    public void onColorsChanged(SparseIntArray colors) {
-        if (isDeferringUpdates()) {
-            mDeferredColorChange = colors;
-            mHasDeferredColorChange = true;
-            return;
-        }
-        mDeferredColorChange = null;
-        mHasDeferredColorChange = false;
-
-        // setColorResources will reapply the view, which must happen in the UI thread.
-        post(() -> setColorResources(colors));
-    }
-
-    @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(getClass().getName());
diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java
index 96e7531..7b500c7 100644
--- a/src/com/android/launcher3/widget/LocalColorExtractor.java
+++ b/src/com/android/launcher3/widget/LocalColorExtractor.java
@@ -17,11 +17,8 @@
 package com.android.launcher3.widget;
 
 import android.app.WallpaperColors;
-import android.appwidget.AppWidgetHostView;
 import android.content.Context;
-import android.graphics.Rect;
 import android.util.SparseIntArray;
-import android.view.View;
 
 import androidx.annotation.Nullable;
 
@@ -31,18 +28,6 @@
 /** Extracts the colors we need from the wallpaper at given locations. */
 public class LocalColorExtractor implements ResourceBasedOverride {
 
-    /** Listener for color changes on a screen location. */
-    public interface Listener {
-        /**
-         * Method called when the colors on a registered location has changed.
-         *
-         * {@code extractedColors} maps the color resources {@code android.R.colors.system_*} to
-         * their value, in a format that can be passed directly to
-         * {@link AppWidgetHostView#setColorResources(SparseIntArray)}.
-         */
-        void onColorsChanged(SparseIntArray extractedColors);
-    }
-
     /**
      * Creates a new instance of LocalColorExtractor
      */
@@ -51,19 +36,6 @@
                 R.string.local_colors_extraction_class);
     }
 
-    /** Sets the object that will receive the color changes. */
-    public void setListener(@Nullable Listener listener) {
-        // no-op
-    }
-
-    /**
-     * Sets the location used for color extraction
-     * @param pos position to use for color extraction
-     * @param child view whose coordinate space is used for {@code pos}
-     * @param screenId the workspace screenId
-     */
-    public void setWorkspaceLocation(Rect pos, View child, int screenId) { }
-
     /**
      * Updates the base context to contain the colors override
      */
@@ -76,5 +48,4 @@
     public SparseIntArray generateColorsOverride(WallpaperColors colors) {
         return null;
     }
-
 }
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index faad307..8857774 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.RoundDrawableWrapper;
-import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
 
 /**
  * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
@@ -132,8 +131,6 @@
             }
             if (mAppWidgetHostViewPreview != null) {
                 previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
-                launcher.getDragController()
-                        .addDragListener(new AppWidgetHostViewDragListener(launcher));
             }
             if (preview == null && mAppWidgetHostViewPreview == null) {
                 Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher)
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index ab007fb..eac2ce7 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -23,8 +23,13 @@
 import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
 import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -45,11 +50,13 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.launcher3.CheckLongPressHelper;
 import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedPropertySetter;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.RoundDrawableWrapper;
 import com.android.launcher3.model.WidgetItem;
@@ -77,7 +84,7 @@
     private static final boolean DEBUG = false;
 
     private static final int FADE_IN_DURATION_MS = 90;
-    private static final int ADD_BUTTON_FADE_DURATION_MS = 300;
+    private static final int ADD_BUTTON_FADE_DURATION_MS = 100;
 
     /**
      * The requested scale of the preview container. It can be lower than this as well.
@@ -110,6 +117,7 @@
     private int mSourceContainer = CONTAINER_WIDGETS_TRAY;
 
     private CancellableTask mIconLoadRequest;
+    private boolean mIsShowingAddButton = false;
 
     public WidgetCell(Context context) {
         this(context, null);
@@ -495,6 +503,15 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+
+        if (changed && isShowingAddButton()) {
+            post(this::setupIconOrTextButton);
+        }
+    }
+
     /**
      * Loads a high resolution package icon to show next to the widget title.
      */
@@ -534,30 +551,57 @@
      * @param callback Callback to be set on the button.
      */
     public void showAddButton(View.OnClickListener callback) {
-        mWidgetAddButton.setAlpha(0F);
-        mWidgetAddButton.setVisibility(VISIBLE);
-        mWidgetAddButton.setOnClickListener(callback);
-        mWidgetAddButton.animate().cancel();
-        mWidgetAddButton.animate()
-                .alpha(1F)
-                .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+        if (mIsShowingAddButton) return;
+        mIsShowingAddButton = true;
 
-        mWidgetTextContainer.animate().cancel();
-        mWidgetTextContainer.animate()
-                .alpha(0F)
-                .setDuration(ADD_BUTTON_FADE_DURATION_MS)
-                .withEndAction(() -> {
-                    mWidgetTextContainer.setVisibility(INVISIBLE);
-                });
+        setupIconOrTextButton();
+        mWidgetAddButton.setOnClickListener(callback);
+        fadeThrough(/* hide= */ mWidgetTextContainer, /* show= */ mWidgetAddButton,
+                ADD_BUTTON_FADE_DURATION_MS, Interpolators.LINEAR);
+    }
+
+    /**
+     * Depending on the width of the cell, set up the add button to be icon-only or icon+text.
+     */
+    private void setupIconOrTextButton() {
+        String addText = getResources().getString(R.string.widget_add_button_label);
+        Rect textSize = new Rect();
+        mWidgetAddButton.getPaint().getTextBounds(addText, 0, addText.length(), textSize);
+        int startPadding = getResources()
+                .getDimensionPixelSize(R.dimen.widget_cell_add_button_start_padding);
+        int endPadding = getResources()
+                .getDimensionPixelSize(R.dimen.widget_cell_add_button_end_padding);
+        int drawableWidth = getResources()
+                .getDimensionPixelSize(R.dimen.widget_cell_add_button_drawable_width);
+        int drawablePadding = getResources()
+                .getDimensionPixelSize(R.dimen.widget_cell_add_button_drawable_padding);
+        int textButtonWidth = textSize.width() + startPadding + endPadding + drawableWidth
+                + drawablePadding;
+        if (textButtonWidth > getMeasuredWidth()) {
+            // Setup icon-only button
+            mWidgetAddButton.setText(null);
+            int startIconPadding = getResources()
+                    .getDimensionPixelSize(R.dimen.widget_cell_add_icon_button_start_padding);
+            mWidgetAddButton.setPaddingRelative(/* start= */ startIconPadding, /* top= */ 0,
+                    /* end= */ endPadding, /* bottom= */ 0);
+            mWidgetAddButton.setCompoundDrawablePadding(0);
+        } else {
+            // Setup icon + text button
+            mWidgetAddButton.setText(addText);
+            mWidgetAddButton.setPaddingRelative(/* start= */ startPadding, /* top= */ 0,
+                    /* end= */ endPadding, /* bottom= */ 0);
+            mWidgetAddButton.setCompoundDrawablePadding(drawablePadding);
+        }
     }
 
     /**
      * Hide tap to add button.
      */
     public void hideAddButton(boolean animate) {
+        if (!mIsShowingAddButton) return;
+        mIsShowingAddButton = false;
+
         mWidgetAddButton.setOnClickListener(null);
-        mWidgetAddButton.animate().cancel();
-        mWidgetTextContainer.animate().cancel();
 
         if (!animate) {
             mWidgetAddButton.setVisibility(INVISIBLE);
@@ -566,17 +610,45 @@
             return;
         }
 
-        mWidgetAddButton.animate()
-                .alpha(0F)
-                .setDuration(ADD_BUTTON_FADE_DURATION_MS)
-                .withEndAction(() -> {
-                    mWidgetAddButton.setVisibility(INVISIBLE);
-                });
+        fadeThrough(/* hide= */ mWidgetAddButton, /* show= */ mWidgetTextContainer,
+                ADD_BUTTON_FADE_DURATION_MS, Interpolators.LINEAR);
+    }
 
-        mWidgetTextContainer.setAlpha(0F);
-        mWidgetTextContainer.setVisibility(VISIBLE);
-        mWidgetTextContainer.animate()
-                .alpha(1F)
-                .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+    public boolean isShowingAddButton() {
+        return mIsShowingAddButton;
+    }
+
+    private static void fadeThrough(View hide, View show, int durationMs,
+            TimeInterpolator interpolator) {
+        AnimatedPropertySetter setter = new AnimatedPropertySetter();
+
+        Animator hideAnim = setter.setViewAlpha(hide, 0F, interpolator).setDuration(durationMs);
+        if (hideAnim instanceof ObjectAnimator anim) {
+            anim.setAutoCancel(true);
+        }
+
+        Animator showAnim = setter.setViewAlpha(show, 1F, interpolator).setDuration(durationMs);
+        if (showAnim instanceof ObjectAnimator anim) {
+            anim.setAutoCancel(true);
+        }
+
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(hideAnim, showAnim);
+        set.start();
+    }
+
+    /**
+     * Returns true if this WidgetCell is displaying the same item as info.
+     */
+    public boolean matchesItem(WidgetItem info) {
+        if (info == null || mItem == null) return false;
+        if (info.widgetInfo != null && mItem.widgetInfo != null) {
+            return info.widgetInfo.getUser().equals(mItem.widgetInfo.getUser())
+                    && info.widgetInfo.getComponent().equals(mItem.widgetInfo.getComponent());
+        } else if (info.activityInfo != null && mItem.activityInfo != null) {
+            return info.activityInfo.getUser().equals(mItem.activityInfo.getUser())
+                    && info.activityInfo.getComponent().equals(mItem.activityInfo.getComponent());
+        }
+        return false;
     }
 }
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index d293d15..9132b4f 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -26,6 +26,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.util.Log;
 import android.widget.RemoteViews;
 
 import androidx.annotation.NonNull;
@@ -104,6 +105,8 @@
             // If exception is thrown because of device is locked, it means a race condition occurs
             // that the user got locked again while launcher is processing the event. In this case
             // we should return empty list.
+            Log.e(TAG, "getAllProviders: Error getting installed providers for"
+                    + " package=" + packageUser.mPackageName, e);
             return Collections.emptyList();
         }
     }
@@ -133,6 +136,8 @@
                 return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
             }
         }
+        Log.w(TAG, "findProvider: No App Widget Provider found for component=" + provider
+                + " user=" + user);
         return null;
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index f1b80e4..4ea2426 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -21,13 +21,13 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.animation.Interpolator;
 import android.widget.ScrollView;
 import android.widget.TableLayout;
@@ -49,57 +49,11 @@
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
 public class WidgetsBottomSheet extends BaseWidgetSheet {
-    private static final String TAG = "WidgetsBottomSheet";
-
-    private static final IntProperty<View> PADDING_BOTTOM =
-            new IntProperty<View>("paddingBottom") {
-                @Override
-                public void setValue(View view, int paddingBottom) {
-                    view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
-                            view.getPaddingRight(), paddingBottom);
-                }
-
-                @Override
-                public Integer get(View view) {
-                    return view.getPaddingBottom();
-                }
-            };
-
     private static final int DEFAULT_CLOSE_DURATION = 200;
-    private static final long EDUCATION_TIP_DELAY_MS = 300;
 
     private ItemInfo mOriginalItemInfo;
     @Px private int mMaxHorizontalSpan;
 
-    private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
-            new OnLayoutChangeListener() {
-                @Override
-                public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    if (hasSeenEducationTip()) {
-                        removeOnLayoutChangeListener(this);
-                        return;
-                    }
-                    // Widgets are loaded asynchronously, We are adding a delay because we only want
-                    // to show the tip when the widget preview has finished loading and rendering in
-                    // this view.
-                    removeCallbacks(mShowEducationTipTask);
-                    postDelayed(mShowEducationTipTask, EDUCATION_TIP_DELAY_MS);
-                }
-            };
-
-    private final Runnable mShowEducationTipTask = () -> {
-        if (hasSeenEducationTip()) {
-            removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-            return;
-        }
-        View viewForTip = ((ViewGroup) ((TableLayout) findViewById(R.id.widgets_table))
-                                    .getChildAt(0)).getChildAt(0);
-        if (showEducationTipOnViewIfPossible(viewForTip) != null) {
-            removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-        }
-    };
-
     public WidgetsBottomSheet(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -107,9 +61,6 @@
     public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
-        if (!hasSeenEducationTip()) {
-            addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-        }
     }
 
     @Override
@@ -118,9 +69,6 @@
         mContent = findViewById(R.id.widgets_bottom_sheet);
         setContentBackgroundWithParent(
                 getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet), mContent);
-        View scrollView = findViewById(R.id.widgets_table_scroll_view);
-        scrollView.setOutlineProvider(mViewOutlineProvider);
-        scrollView.setClipToOutline(true);
     }
 
     @Override
@@ -194,6 +142,9 @@
                     row.forEach(widgetItem -> {
                         WidgetCell widget = addItemCell(tableRow);
                         widget.applyFromCellItem(widgetItem);
+                        if (widget.matchesItem(getLastSelectedWidgetItem())) {
+                            widget.callOnClick();
+                        }
                     });
                     widgetsTable.addView(tableRow);
                 });
@@ -215,6 +166,7 @@
     protected WidgetCell addItemCell(ViewGroup parent) {
         WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
                 .inflate(R.layout.widget_cell, parent, false);
+        widget.setOnClickListener(this);
 
         View previewContainer = widget.findViewById(R.id.widget_preview_container);
         previewContainer.setOnClickListener(this);
@@ -282,4 +234,16 @@
             float distanceToMove, Interpolator interpolator, PendingAnimation target) {
         target.addAnimatedFloat(mSwipeToDismissProgress, 0f, 1f, interpolator);
     }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof ScrollView scrollView) {
+                scrollView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 05fe8e3..50012b3 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.widget.custom;
 
-import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
 import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
 import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
 
@@ -70,7 +70,7 @@
         PluginManagerWrapper.INSTANCE.get(context)
                 .addPluginListener(this, CustomWidgetPlugin.class, true);
 
-        if (SMARTSPACE_AS_A_WIDGET.get()) {
+        if (enableSmartspaceAsAWidget()) {
             for (String s: context.getResources()
                     .getStringArray(R.array.custom_widget_providers)) {
                 try {
diff --git a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
deleted file mode 100644
index 3e54b33..0000000
--- a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.dragndrop;
-
-import com.android.launcher3.DropTarget;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
-
-/** A drag listener of {@link LauncherAppWidgetHostView}. */
-public final class AppWidgetHostViewDragListener implements DragController.DragListener {
-    private final Launcher mLauncher;
-    private LauncherAppWidgetHostView mAppWidgetHostView;
-
-    public AppWidgetHostViewDragListener(Launcher launcher) {
-        mLauncher = launcher;
-    }
-
-    @Override
-    public void onDragStart(DropTarget.DragObject dragObject, DragOptions unused) {
-        if (dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView) {
-            mAppWidgetHostView = (LauncherAppWidgetHostView) dragObject.dragView.getContentView();
-            mAppWidgetHostView.startDrag();
-        } else {
-            mLauncher.getDragController().removeDragListener(this);
-        }
-    }
-
-    @Override
-    public void onDragEnd() {
-        mAppWidgetHostView.endDrag();
-        mLauncher.getDragController().removeDragListener(this);
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
index c3906a6..80bda22 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -62,16 +62,17 @@
         // via the overridden WidgetRecommendationCategoryProvider resource.
 
         Preconditions.assertWorkerThread();
-        PackageManagerHelper pmHelper = new PackageManagerHelper(context);
-        if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
-            String widgetComponentName = item.widgetInfo.getComponent().getClassName();
-            ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
-                    item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
-                    0 /* flags */);
-            if (applicationInfo != null) {
-                int predictionCategory = applicationInfo.category;
-                return getCategoryFromApplicationCategory(context, predictionCategory,
-                        widgetComponentName);
+        try (PackageManagerHelper pmHelper = new PackageManagerHelper(context)) {
+            if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
+                String widgetComponentName = item.widgetInfo.getComponent().getClassName();
+                ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
+                        item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
+                        0 /* flags */);
+                if (applicationInfo != null) {
+                    int predictionCategory = applicationInfo.category;
+                    return getCategoryFromApplicationCategory(context, predictionCategory,
+                            widgetComponentName);
+                }
             }
         }
         return null;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c3067a5..6aaa7d2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,10 +17,10 @@
 
 import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
 import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
-import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_LIST;
 
 import android.animation.Animator;
 import android.content.Context;
@@ -38,6 +38,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
 import android.view.animation.AnimationUtils;
@@ -46,6 +47,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
@@ -55,20 +57,17 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.model.UserManagerState;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.views.ArrowTipView;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
 import com.android.launcher3.views.StickyHeaderLayout;
-import com.android.launcher3.views.WidgetsEduView;
 import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.picker.search.SearchModeListener;
 import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
@@ -90,8 +89,6 @@
         WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
 
     private static final long FADE_IN_DURATION = 150;
-    private static final long EDUCATION_TIP_DELAY_MS = 200;
-    private static final long EDUCATION_DIALOG_DELAY_MS = 500;
 
     // The widget recommendation table can easily take over the entire screen on devices with small
     // resolution or landscape on phone. This ratio defines the max percentage of content area that
@@ -114,36 +111,6 @@
             new HashMap<>();
     protected int mRecommendationsCurrentPage = 0;
     protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
-    @Nullable
-    private ArrowTipView mLatestEducationalTip;
-    private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
-            new OnLayoutChangeListener() {
-                @Override
-                public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    if (hasSeenEducationTip()) {
-                        removeOnLayoutChangeListener(this);
-                        return;
-                    }
-
-                    // Widgets are loaded asynchronously, We are adding a delay because we only want
-                    // to show the tip when the widget preview has finished loading and rendering in
-                    // this view.
-                    removeCallbacks(mShowEducationTipTask);
-                    postDelayed(mShowEducationTipTask, EDUCATION_TIP_DELAY_MS);
-                }
-            };
-
-    private final Runnable mShowEducationTipTask = () -> {
-        if (hasSeenEducationTip()) {
-            removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-            return;
-        }
-        mLatestEducationalTip = showEducationTipOnViewIfPossible(getViewToShowEducationTip());
-        if (mLatestEducationalTip != null) {
-            removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-        }
-    };
 
     private final OnAttachStateChangeListener mBindScrollbarInSearchMode =
             new OnAttachStateChangeListener() {
@@ -248,7 +215,6 @@
         mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
 
         onWidgetsBound();
-        setUpEducationViewsIfNeeded();
     }
 
     protected void setupViews() {
@@ -813,10 +779,6 @@
     @Override
     protected void onCloseComplete() {
         super.onCloseComplete();
-        removeCallbacks(mShowEducationTipTask);
-        if (mLatestEducationalTip != null) {
-            mLatestEducationalTip.close(true);
-        }
         AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
     }
 
@@ -899,11 +861,23 @@
         return isFoldUnFold || useDifferentLayoutOnOrientationChange;
     }
 
+    /**
+     * In widget search mode, we should scale down content inside widget bottom sheet, rather
+     * than the whole bottom sheet, to indicate we will navigate back within the widget
+     * bottom sheet.
+     */
+    @Override
+    public boolean shouldAnimateContentViewInBackSwipe() {
+        return mIsInSearchMode;
+    }
+
     @Override
     public void onBackInvoked() {
         if (mIsInSearchMode) {
             mSearchBar.reset();
-            animateSwipeToDismissProgressToStart();
+            // Posting animation to next frame will let widget sheet finish updating UI first, and
+            // make animation smoother.
+            post(this::animateSwipeToDismissProgressToStart);
         } else {
             super.onBackInvoked();
         }
@@ -944,36 +918,6 @@
         return null;
     }
 
-    /** Shows education dialog for widgets. */
-    private WidgetsEduView showEducationDialog() {
-        LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_DIALOG_SEEN, true);
-        return WidgetsEduView.showEducationDialog(mActivityContext);
-    }
-
-    /** Returns {@code true} if education dialog has previously been shown. */
-    protected boolean hasSeenEducationDialog() {
-        return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_DIALOG_SEEN)
-                || Utilities.isRunningInTestHarness();
-    }
-
-    protected void setUpEducationViewsIfNeeded() {
-        if (!hasSeenEducationDialog()) {
-            postDelayed(() -> {
-                WidgetsEduView eduDialog = showEducationDialog();
-                eduDialog.addOnCloseListener(() -> {
-                    if (!hasSeenEducationTip()) {
-                        addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-                        // Call #requestLayout() to trigger layout change listener in order to show
-                        // arrow tip immediately if there is a widget to show it on.
-                        requestLayout();
-                    }
-                });
-            }, EDUCATION_DIALOG_DELAY_MS);
-        } else if (!hasSeenEducationTip()) {
-            addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-        }
-    }
-
     protected boolean isTwoPane() {
         return false;
     }
@@ -991,6 +935,60 @@
         mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
     }
 
+    @Override
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        StickyHeaderLayout header = findViewById(R.id.search_and_recommendations_container);
+        if (header == null) {
+            return 0;
+        }
+        Rect cellRect = new Rect();
+        boolean cellIsPartiallyVisible = cell.getGlobalVisibleRect(cellRect);
+        if (cellIsPartiallyVisible) {
+            Rect occludingRect = new Rect();
+            for (View headerChild : header.getStickyChildren()) {
+                Rect childRect = new Rect();
+                boolean childVisible = headerChild.getGlobalVisibleRect(childRect);
+                if (childVisible && childRect.intersect(cellRect)) {
+                    occludingRect.union(childRect);
+                }
+            }
+            if (!occludingRect.isEmpty() && cellRect.top < occludingRect.bottom) {
+                return occludingRect.bottom - cellRect.top;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof WidgetsRecyclerView recyclerView) {
+                // Scrollable container for main widget list.
+                recyclerView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent instanceof StickyHeaderLayout header) {
+                // Scrollable container for recommendations. We still scroll on the recycler (even
+                // though the recommendations are not in the recycler view) because the
+                // StickyHeaderLayout scroll is connected to the currently visible recycler view.
+                WidgetsRecyclerView recyclerView = findVisibleRecyclerView();
+                if (recyclerView != null) {
+                    recyclerView.smoothScrollBy(0, scrollByY);
+                }
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
+    }
+
+    @Nullable
+    private WidgetsRecyclerView findVisibleRecyclerView() {
+        if (mViewPager != null) {
+            return (WidgetsRecyclerView) mViewPager.getPageAt(mViewPager.getCurrentPage());
+        }
+        return findViewById(R.id.primary_widgets_list_view);
+    }
+
     /** A holder class for holding adapters & their corresponding recycler view. */
     final class AdapterHolder {
         static final int PRIMARY = 0;
@@ -1025,10 +1023,35 @@
                 default:
                     break;
             }
-            mWidgetsListItemAnimator = new DefaultItemAnimator();
+            mWidgetsListItemAnimator = new DefaultItemAnimator() {
+                @Override
+                public boolean animateChange(RecyclerView.ViewHolder oldHolder,
+                        RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft,
+                        int toTop) {
+                    // As we expand an item, the content / widgets list that appears (with add
+                    // event) also gets change events as its previews load asynchronously. The
+                    // super implementation of animateChange cancels the animations on it - breaking
+                    // the "add animation". Instead, here, we skip "change" animation for content
+                    // list - because we want it to either appear or disappear. And, the previews
+                    // themselves have their own animation when loaded, so, we don't need change
+                    // animations for them anyway. Below, we do-nothing.
+                    if (oldHolder.getItemViewType() == VIEW_TYPE_WIDGETS_LIST) {
+                        dispatchChangeStarting(oldHolder, true);
+                        dispatchChangeFinished(oldHolder, true);
+                        return true;
+                    }
+                    return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft,
+                            toTop);
+                }
+            };
             // Disable change animations because it disrupts the item focus upon adapter item
             // change.
             mWidgetsListItemAnimator.setSupportsChangeAnimations(false);
+            // Make the moves a bit faster, so that the amount of time for which user sees the
+            // bottom-sheet background before "add" animation starts is less making it smoother.
+            mWidgetsListItemAnimator.setChangeDuration(90);
+            mWidgetsListItemAnimator.setMoveDuration(90);
+            mWidgetsListItemAnimator.setAddDuration(300);
         }
 
         private int getEmptySpaceHeight() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index a7f7785..56352cc 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -160,6 +160,7 @@
                     WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
                             R.layout.widget_cell, tableRow, false);
                     // set up touch.
+                    widget.setOnClickListener(mIconClickListener);
                     View preview = widget.findViewById(R.id.widget_preview_container);
                     preview.setOnClickListener(mIconClickListener);
                     preview.setOnLongClickListener(mIconLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index a565780..6dbad5c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -58,12 +58,13 @@
 
     public WidgetsRecommendationTableLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
-        // There are 1 row for title, 1 row for dimension and 2 rows for description.
+        // There are 1 row for title, 1 row for dimension and max 3 rows for description.
         mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
                 .getDimensionPixelSize(R.dimen.widget_recommendations_table_vertical_padding);
         mWidgetCellVerticalPadding = 2 * getResources()
                 .getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
-        mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
+        mWidgetCellTextViewsHeight =
+                getResources().getDimension(R.dimen.widget_cell_title_line_height);
     }
 
     /** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
@@ -123,6 +124,7 @@
     private WidgetCell addItemCell(ViewGroup parent) {
         WidgetCell widget = (WidgetCell) LayoutInflater.from(
                 getContext()).inflate(R.layout.widget_cell, parent, false);
+        widget.setOnClickListener(mWidgetCellOnClickListener);
 
         View previewContainer = widget.findViewById(R.id.widget_preview_container);
         previewContainer.setOnClickListener(mWidgetCellOnClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 698e764..a47818f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -73,7 +73,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
     @Override
-    public String scrollToPositionAtProgress(float touchFraction) {
+    public CharSequence scrollToPositionAtProgress(float touchFraction) {
         // Skip early if widgets are not bound.
         if (isModelNotReady()) {
             return "";
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 14985bf..f835e18 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -23,27 +23,30 @@
 import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
 
 import android.content.Context;
-import android.graphics.Outline;
 import android.graphics.Rect;
 import android.os.Process;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewOutlineProvider;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
@@ -64,7 +67,7 @@
 
     // This ratio defines the max percentage of content area that the recommendations can display
     // with respect to the bottom sheet's height.
-    private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.75f;
+    private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.60f;
     private FrameLayout mSuggestedWidgetsContainer;
     private WidgetsListHeader mSuggestedWidgetsHeader;
     private PackageUserKey mSuggestedWidgetsPackageUserKey;
@@ -76,23 +79,9 @@
 
     private boolean mOldIsSwipeToDismissInProgress;
     private int mActivePage = -1;
+    @Nullable
     private PackageUserKey mSelectedHeader;
 
-    private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            outline.setRoundRect(
-                    0,
-                    0,
-                    view.getMeasuredWidth(),
-                    view.getMeasuredHeight() - getResources().getDimensionPixelSize(
-                            R.dimen.widget_list_horizontal_margin_two_pane),
-                    view.getResources().getDimensionPixelSize(
-                            R.dimen.widget_list_top_bottom_corner_radius)
-            );
-        }
-    };
-
     public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
@@ -136,24 +125,40 @@
 
         mHeaderTitle = mContent.findViewById(R.id.title);
         mRightPane = mContent.findViewById(R.id.right_pane);
-        mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
         mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
         mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
-        mRightPaneScrollView.setOutlineProvider(mViewOutlineProvider);
-        mRightPaneScrollView.setClipToOutline(true);
 
         mPrimaryWidgetListView = findViewById(R.id.primary_widgets_list_view);
         mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider);
         mPrimaryWidgetListView.setClipToOutline(true);
 
         onWidgetsBound();
-        setUpEducationViewsIfNeeded();
 
         // Set the fast scroller as not visible for two pane layout.
         mFastScroller.setVisibility(GONE);
     }
 
     @Override
+    protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
+        if (enableCategorizedWidgetSuggestions()) {
+            // two pane picker is full width for fold as well as tablet.
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_two_panels_left_right_margin);
+        }
+        if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            // enableUnfoldedTwoPanePicker made two pane picker full-width for fold only.
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_two_panels_left_right_margin);
+        }
+        if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+            // non-fold tablet landscape margins (ag/22163531)
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_landscape_tablet_left_right_margin);
+        }
+        return deviceProfile.allAppsLeftRightMargin;
+    }
+
+    @Override
     protected void onUserSwipeToDismissProgressChanged() {
         super.onUserSwipeToDismissProgressChanged();
         boolean isSwipeToDismissInProgress = mSwipeToDismissProgress.value > 0;
@@ -193,15 +198,21 @@
                 layoutParams.width = 0;
             }
             layoutParams.weight = layoutParams.width == 0 ? 0.33F : 0;
-            leftPane.setLayoutParams(layoutParams);
-            requestApplyInsets();
-            if (mSelectedHeader != null) {
-                if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
-                    mSuggestedWidgetsHeader.callOnClick();
-                } else {
-                    getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
+
+            post(() -> {
+                // The following calls all trigger requestLayout, so we post them to avoid
+                // calling requestLayout during a layout pass. This also fixes the related warnings
+                // in logcat.
+                leftPane.setLayoutParams(layoutParams);
+                requestApplyInsets();
+                if (mSelectedHeader != null) {
+                    if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
+                        mSuggestedWidgetsHeader.callOnClick();
+                    } else {
+                        getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
+                    }
                 }
-            }
+            });
         }
     }
 
@@ -221,6 +232,10 @@
         if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
             setupSuggestedWidgets(LayoutInflater.from(getContext()));
             mSuggestedWidgetsHeader.callOnClick();
+        } else if (mSelectedHeader != null
+                && mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
+            // Reselect widget if we are reloading recommendations while it is currently showing.
+            selectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
         }
     }
 
@@ -268,6 +283,16 @@
             mRightPaneScrollView.setScrollY(0);
             mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
             mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
+            final boolean isChangingHeaders = mSelectedHeader == null
+                    || !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
+            if (isChangingHeaders)  {
+                // If switching from another header, unselect any WidgetCells. This is necessary
+                // because we do not clear/recycle the WidgetCells in the recommendations container
+                // when the header is clicked, only when onRecommendationsBound is called. That
+                // means a WidgetCell in the recommendations container may still be selected from
+                // the last time the recommendations were shown.
+                unselectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
+            }
             mSelectedHeader = mSuggestedWidgetsPackageUserKey;
         });
         mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
@@ -356,6 +381,8 @@
         return new HeaderChangeListener() {
             @Override
             public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+                final boolean isSameHeader = mSelectedHeader != null
+                        && mSelectedHeader.equals(selectedHeader);
                 mSelectedHeader = selectedHeader;
                 WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
                         .getSelectedAppWidgets(selectedHeader);
@@ -383,11 +410,20 @@
                         contentEntryToBind,
                         ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
                         Collections.EMPTY_LIST);
+                if (isSameHeader) {
+                    // Reselect the last selected widget if we are reloading the same header.
+                    selectWidgetCell(widgetsRowViewHolder.tableContainer,
+                            getLastSelectedWidgetItem());
+                }
                 widgetsRowViewHolder.mDataCallback = data -> {
                     mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
                             contentEntryToBind,
                             ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
                             Collections.singletonList(data));
+                    if (isSameHeader) {
+                        selectWidgetCell(widgetsRowViewHolder.tableContainer,
+                                getLastSelectedWidgetItem());
+                    }
                 };
                 mRightPane.removeAllViews();
                 mRightPane.addView(widgetsRowViewHolder.itemView);
@@ -400,6 +436,24 @@
         };
     }
 
+    private static void selectWidgetCell(ViewGroup parent, WidgetItem item) {
+        if (parent == null || item == null) return;
+        WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
+                && wc.matchesItem(item));
+        if (cell != null && !cell.isShowingAddButton()) {
+            cell.callOnClick();
+        }
+    }
+
+    private static void unselectWidgetCell(ViewGroup parent, WidgetItem item) {
+        if (parent == null || item == null) return;
+        WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
+                && wc.matchesItem(item));
+        if (cell != null && cell.isShowingAddButton()) {
+            cell.hideAddButton(/* animate= */ false);
+        }
+    }
+
     @Override
     public void setInsets(Rect insets) {
         super.setInsets(insets);
@@ -423,6 +477,23 @@
         return true;
     }
 
+    @Override
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        return 0;
+    }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof ScrollView scrollView) {
+                scrollView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
+    }
+
     /**
      * This is a listener for when the selected header gets changed in the left pane.
      */
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index 5e0e203..edaf474 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -31,6 +31,7 @@
 
 /** An utility class which groups {@link WidgetItem}s into a table. */
 public final class WidgetsTableUtils {
+    private static final int MAX_ITEMS_IN_ROW = 3;
 
     /**
      * Groups widgets in the following order:
@@ -125,7 +126,8 @@
                 widgetItemsAtRow.add(widgetItem);
                 containerSizeForRow = containerSize;
                 currentRowWidth = containerWidth;
-            } else if ((currentRowWidth + containerWidth) <= rowPx
+            } else if (widgetItemsAtRow.size() < MAX_ITEMS_IN_ROW
+                    && (currentRowWidth + containerWidth) <= rowPx
                     && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
                     && containerSize.equals(containerSizeForRow)) {
                 // Group items in the same row if
diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/PredictedAppIconInflater.java b/src_no_quickstep/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
deleted file mode 100644
index 4893c17..0000000
--- a/src_no_quickstep/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.uioverrides;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-
-/** A util class that inflates a predicted app icon */
-public class PredictedAppIconInflater {
-    public static View inflate(LayoutInflater inflater, ViewGroup parent, WorkspaceItemInfo info) {
-        return null;
-    }
-}
diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/src_no_quickstep/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
deleted file mode 100644
index 6afa446..0000000
--- a/src_no_quickstep/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ /dev/null
@@ -1,27 +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.uioverrides.flags;
-
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-
-/**
- * Place holder class for developer options.
- */
-public class DeveloperOptionsUI {
-
-    public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) { }
-}
diff --git a/tests/Android.bp b/tests/Android.bp
index 3822ff8..11177de 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -23,7 +23,8 @@
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
-        ":launcher3-robo-src",
+        "multivalentTests/src/**/*.java",
+        "multivalentTests/src/**/*.kt",
     ],
     exclude_srcs: [
         ":launcher-non-quickstep-tests-src",
@@ -37,6 +38,8 @@
     srcs: [
         "multivalentTests/src/**/*.java",
         "multivalentTests/src/**/*.kt",
+        "src_deviceless/**/*.java",
+        "src_deviceless/**/*.kt",
     ],
 }
 
@@ -102,6 +105,7 @@
 android_library {
     name: "Launcher3TestResources",
     resource_dirs: ["res"],
+    asset_dirs: ["assets"],
     // TODO(b/319712088): re-enable use_resource_processor
     use_resource_processor: false,
 }
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 27dd2a9..8c5195e 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -319,6 +319,15 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity-alias>
+        <activity-alias android:name="ActivityNoLabel"
+            android:label=""
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
         <activity-alias android:name="MaxShortcutsActivity"
             android:label="TestActivityMaxShortcuts"
             android:exported="true"
@@ -403,5 +412,9 @@
             android:name="androidx.startup.InitializationProvider"
             android:authorities="${applicationId}.androidx-startup"
             tools:node="remove" />
+
+        <property
+            android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
+            android:value="true"/>
     </application>
 </manifest>
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 29c34be..270a610 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -44,6 +44,8 @@
         <option name="run-command" value="settings put global airplane_mode_on 1" />
         <option name="run-command" value="am broadcast -a android.intent.action.AIRPLANE_MODE" />
 
+        <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
+
         <option name="run-command" value="settings put system pointer_location 1" />
         <option name="run-command" value="settings put system show_touches 1" />
     </target_preparer>
diff --git a/tests/OWNERS b/tests/OWNERS
index b5ee7d7..6b8643c 100644
--- a/tests/OWNERS
+++ b/tests/OWNERS
@@ -3,4 +3,3 @@
 sunnygoyal@google.com
 winsonc@google.com
 hyunyoungs@google.com
-mateuszc@google.com
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index 197e687..82a6310 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 273.0px (104.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index 4a9e2e6..4271105 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 294.0px (112.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 147.0px (56.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index 9e89a16..8bd6b99 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 252.0px (96.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 0.0px (0.0dp)
 	mHotseatBarEdgePaddingPx: 63.0px (24.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index ce168b4..8dbb413 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 252.0px (96.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 0.0px (0.0dp)
 	mHotseatBarEdgePaddingPx: 63.0px (24.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index 7926033..ab4b286 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 412.0px (206.0dp)
 	hotseatBarSizePx: 200.0px (100.0dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1960.0px (980.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 80.0px (40.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -82,12 +83,12 @@
 	springLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)
-	getHotseatLayoutPadding(context).left: 668.0px (334.0dp)
-	getHotseatLayoutPadding(context).right: 668.0px (334.0dp)
+	getHotseatLayoutPadding(context).left: 300.0px (150.0dp)
+	getHotseatLayoutPadding(context).right: 300.0px (150.0dp)
 	numShownHotseatIcons: 6
-	hotseatBorderSpace: 100.0px (50.0dp)
+	hotseatBorderSpace: 248.0px (124.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1214.0px (607.0dp)
+	hotseatQsbWidth: 1950.0px (975.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index eb20578..80835bc 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 412.0px (206.0dp)
 	hotseatBarSizePx: 200.0px (100.0dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1960.0px (980.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 80.0px (40.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -82,12 +83,12 @@
 	springLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)
-	getHotseatLayoutPadding(context).left: 668.0px (334.0dp)
-	getHotseatLayoutPadding(context).right: 668.0px (334.0dp)
+	getHotseatLayoutPadding(context).left: 300.0px (150.0dp)
+	getHotseatLayoutPadding(context).right: 300.0px (150.0dp)
 	numShownHotseatIcons: 6
-	hotseatBorderSpace: 100.0px (50.0dp)
+	hotseatBorderSpace: 248.0px (124.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1214.0px (607.0dp)
+	hotseatQsbWidth: 1950.0px (975.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index dba0ec4..fc53107 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 152.0px (76.0dp)
 	hotseatBarSizePx: 272.0px (136.0dp)
-	inv.hotseatColumnSpan: 6
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1300.0px (650.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 152.0px (76.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index 495afb2..836819f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 152.0px (76.0dp)
 	hotseatBarSizePx: 272.0px (136.0dp)
-	inv.hotseatColumnSpan: 6
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1300.0px (650.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 152.0px (76.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index e7dd3e0..108182f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 183.0px (69.71429dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index fcbd427..313d2a3 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 183.0px (69.71429dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 319247c..fb392a8 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 1.0px (0.3809524dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index 50c1d4b..2c4b3c3 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 1.0px (0.3809524dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
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 fea0330..c3b7a2a 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -170,22 +170,12 @@
 
     public static final String PERMANENT_DIAG_TAG = "TaplTarget";
     public static final String TWO_NEXUS_LAUNCHER_ACTIVITY_WHILE_UNLOCKING = "b/273347463";
-    public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
     public static final String ICON_MISSING = "b/282963545";
-    public static final String OVERVIEW_OVER_HOME = "b/279059025";
     public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
-    public static final String GET_FROM_RECENTS_FAILURE = "b/321775748";
-    public static final String SUCCESSFUL_GESTURE_MISMATCH_EVENTS = "b/324940434";
     public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
-    public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
     public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
-    public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
-    public static final String UPDATE_OVERVIEW_TARGETS_RUNNING_LATE = "b/321775748";
-
-    public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
-    public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
-    public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
-    public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
+    public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
+    public static final String CLOCK_ICON_DRAWABLE_LEAKING = "b/319168409";
 
     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/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
diff --git a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
index 13dfd5e..c32461e 100644
--- a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -22,6 +22,8 @@
 import android.view.View
 import androidx.core.view.get
 import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
 import com.android.launcher3.CellLayout
 import com.android.launcher3.celllayout.board.CellLayoutBoard
 import com.android.launcher3.celllayout.board.IconPoint
@@ -34,6 +36,7 @@
 import org.junit.Assert
 import org.junit.Rule
 import org.junit.Test
+import org.junit.runner.RunWith
 
 private class HotseatReorderTestCase(
     val startBoard: CellLayoutBoard,
@@ -44,6 +47,8 @@
     }
 }
 
+@SmallTest
+@RunWith(AndroidJUnit4::class)
 class HotseatReorderUnitTest {
 
     private val applicationContext: Context =
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index 0ff7c20..8a9711d 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -215,9 +215,11 @@
                 testCase.spanX, testCase.spanY, testCase.minSpanX, testCase.minSpanY,
                 isMultiCellLayout);
         assertEquals("should be a valid solution", solution.isSolution, testCase.isValidSolution);
+        Log.d(TAG, "test case:" + testCase);
         if (testCase.isValidSolution) {
             CellLayoutBoard finishBoard = boardFromSolution(solution,
                     testCase.startBoard.getWidth(), testCase.startBoard.getHeight());
+            Log.d(TAG, "finishBoard case:" + finishBoard);
             assertTrue("End result and test case result board doesn't match ",
                     finishBoard.compareTo(testCase.endBoard) == 0);
         }
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
index 0bec1b2..a9355ec 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
@@ -141,11 +141,14 @@
             ReorderPreviewAnimation.MODE_PREVIEW,
             AnimationValues(dx = 0, dy = 0, scale = 100)
         )
-        testAnimationAtGivenProgress(
-            PREVIEW_DURATION * 99,
-            ReorderPreviewAnimation.MODE_PREVIEW,
-            AnimationValues(dx = 5, dy = -10, scale = 96)
-        )
+        // (b/339313407) Temporarily disable this test as the behavior is
+        // inconsistent between Soong & Gradle builds.
+        //
+        // testAnimationAtGivenProgress(
+        //     PREVIEW_DURATION * 99,
+        //     ReorderPreviewAnimation.MODE_PREVIEW,
+        //     AnimationValues(dx = 5, dy = -10, scale = 96)
+        // )
         testAnimationAtGivenProgress(
             PREVIEW_DURATION * 98,
             ReorderPreviewAnimation.MODE_PREVIEW,
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
index fbbfb2a..58dce0b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
@@ -38,7 +38,8 @@
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.util.LauncherMultivalentJUnit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,8 +52,8 @@
  * Tests for FastBitmapDrawable.
  */
 @SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
 @UiThreadTest
-@RunWith(AndroidJUnit4.class)
 public class FastBitmapDrawableTest {
     private static final float EPSILON = 0.00001f;
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt b/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
index 130dfad..713d4d5 100644
--- a/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
@@ -2,8 +2,8 @@
 
 import androidx.core.util.isEmpty
 import androidx.test.annotation.UiThreadTest
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -11,7 +11,7 @@
 
 /** Unit test for [ColdRebootStartupLatencyLogger]. */
 @SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(LauncherMultivalentJUnit::class)
 class StartupLatencyLoggerTest {
 
     private val underTest = ColdRebootStartupLatencyLogger()
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
rename to tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 90ded10..b83349e 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -37,6 +37,9 @@
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.view.ViewGroup;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
@@ -52,6 +55,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.MockitoAnnotations;
 
 /**
@@ -61,6 +65,8 @@
  * two lines, and this is enough to ensure whether the string should be specifically wrapped onto
  * the second line and to ensure truncation.
  */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class BubbleTextViewTest {
 
     @Rule public final SetFlagsRule mSetFlagsRule =
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 0009a4e..f18c02b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -44,25 +44,16 @@
 import android.test.mock.MockContentResolver;
 import android.util.ArrayMap;
 
-import androidx.annotation.NonNull;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.uiautomator.UiDevice;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.testing.TestInformationProvider;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.window.WindowManagerProxy;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -72,7 +63,6 @@
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
 
 /**
  * Utility class to help manage Launcher Model and related objects for test.
@@ -121,17 +111,9 @@
 
     public synchronized BgDataModel getBgDataModel() {
         if (mDataModel == null) {
-            getModel().enqueueModelUpdateTask(new ModelUpdateTask() {
-                @Override
-                public void init(@NonNull LauncherAppState app, @NonNull LauncherModel model,
-                        @NonNull BgDataModel dataModel, @NonNull AllAppsList allAppsList,
-                        @NonNull Executor uiExecutor) {
-                    mDataModel = dataModel;
-                }
-
-                @Override
-                public void run() { }
-            });
+            getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->
+                    mDataModel = dataModel);
+            runOnExecutorSync(Executors.MODEL_EXECUTOR, () -> { });
         }
         return mDataModel;
     }
@@ -233,13 +215,7 @@
         private final File mDbDir;
 
         public SandboxModelContext() {
-            super(ApplicationProvider.getApplicationContext(),
-                    UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
-                    LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
-                    DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
-                    SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
-                    LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
-                    ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
+            super(ApplicationProvider.getApplicationContext());
 
             // System settings cache content provider. Ensure that they are statically initialized
             Settings.Secure.getString(
@@ -254,18 +230,13 @@
         }
 
         @Override
-        protected <T> T createObject(MainThreadInitializedObject<T> object) {
+        public <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
             if (object == LauncherAppState.INSTANCE) {
                 return (T) new LauncherAppState(this, null /* iconCacheFileName */);
             }
             return super.createObject(object);
         }
 
-        public SandboxModelContext allow(MainThreadInitializedObject object) {
-            mAllowedObjects.add(object);
-            return this;
-        }
-
         @Override
         public File getDatabasePath(String name) {
             if (!mDbDir.exists()) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt b/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt
new file mode 100644
index 0000000..e8560af
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.collect.ImmutableList
+import java.util.Locale
+import kotlin.annotation.AnnotationRetention.RUNTIME
+import kotlin.annotation.AnnotationTarget.CLASS
+import org.junit.runner.Runner
+import org.junit.runners.Suite
+
+/**
+ * A custom runner for multivalent tests with launcher specific features
+ * 1) Adds support for @UiThread annotations in deviceless tests
+ * 2) Allows emulating multiple devices when running in deviceless mode
+ */
+class LauncherMultivalentJUnit(klass: Class<*>?) : Suite(klass, ImmutableList.of()) {
+
+    val runners: List<Runner> =
+        (testClass.getAnnotation(EmulatedDevices::class.java)?.value ?: emptyArray()).let { devices
+            ->
+            if (!isRunningInRobolectric) {
+                return@let null
+            }
+            try {
+                (testClass.javaClass.classLoader.loadClass(ROBOLECTRIC_RUNNER) as Class<Runner>)
+                    .getConstructor(Class::class.java, String::class.java)
+                    .let { ctor ->
+                        if (devices.isEmpty()) listOf(ctor.newInstance(testClass.javaClass, null))
+                        else devices.map { ctor.newInstance(testClass.javaClass, it) }
+                    }
+            } catch (e: Exception) {
+                null
+            }
+        }
+            ?: listOf(AndroidJUnit4(testClass.javaClass))
+
+    override fun getChildren() = runners
+
+    /**
+     * Annotation to be added to a test so run it on a list of emulated devices for deviceless test
+     */
+    @Retention(RUNTIME) @Target(CLASS) annotation class EmulatedDevices(val value: Array<String>)
+
+    companion object {
+        private const val ROBOLECTRIC_RUNNER = "com.android.launcher3.util.RobolectricDeviceRunner"
+
+        val isRunningInRobolectric: Boolean
+            get() =
+                if (
+                    System.getProperty("java.runtime.name")
+                        .lowercase(Locale.getDefault())
+                        .contains("android")
+                ) {
+                    false
+                } else {
+                    try {
+                        // Check if robolectric runner exists
+                        Class.forName("org.robolectric.RobolectricTestRunner") != null
+                    } catch (e: ClassNotFoundException) {
+                        false
+                    }
+                }
+    }
+}
diff --git a/tests/res/layout/utilities_test_view.xml b/tests/res/layout/utilities_test_view.xml
new file mode 100644
index 0000000..dc2a515
--- /dev/null
+++ b/tests/res/layout/utilities_test_view.xml
@@ -0,0 +1,33 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/root_view">
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:id="@+id/mid_view">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/child_view" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/shared/com/android/launcher3/testing/OWNERS b/tests/shared/com/android/launcher3/testing/OWNERS
new file mode 100644
index 0000000..02e8ebc
--- /dev/null
+++ b/tests/shared/com/android/launcher3/testing/OWNERS
@@ -0,0 +1,4 @@
+vadimt@google.com
+sunnygoyal@google.com
+winsonc@google.com
+hyunyoungs@google.com
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 577334b..e378733 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -300,18 +300,13 @@
                 smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
             }
         val configurationContext = runningContext.createConfigurationContext(config)
-        context =
-            SandboxContext(
-                configurationContext,
-                DisplayController.INSTANCE,
-                WindowManagerProxy.INSTANCE,
-                LauncherPrefs.INSTANCE
-            )
+        context = SandboxContext(configurationContext)
         context.putObject(DisplayController.INSTANCE, displayController)
         context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
         context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
 
         whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING)).thenReturn(false)
+        whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
         val info = spy(DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache))
         whenever(displayController.info).thenReturn(info)
         whenever(info.isTransientTaskbar).thenReturn(isGestureMode)
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index 251a401..13d7499 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -157,7 +157,6 @@
 
                 numDatabaseHotseatIcons = 4
 
-                hotseatColumnSpan = IntArray(4) { 4 }
                 hotseatBarBottomSpace = FloatArray(4) { 48f }
                 hotseatQsbSpace = FloatArray(4) { 36f }
 
@@ -240,7 +239,6 @@
 
                 numDatabaseHotseatIcons = 6
 
-                hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
                 hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
                 hotseatQsbSpace = FloatArray(4) { 32f }
 
@@ -259,8 +257,10 @@
     }
 
     protected fun initializeVarsForTwoPanel(
-        isLandscape: Boolean = false,
-        isGestureMode: Boolean = true
+            isLandscape: Boolean = false,
+            isGestureMode: Boolean = true,
+            rows: Int = 4,
+            cols: Int = 4,
     ) {
         val (x, y) = if (isLandscape) Pair(2208, 1840) else Pair(1840, 2208)
 
@@ -276,9 +276,9 @@
 
         inv =
             InvariantDeviceProfile().apply {
-                numRows = 4
-                numColumns = 4
-                numSearchContainerColumns = 4
+                numRows = rows
+                numColumns = cols
+                numSearchContainerColumns = cols
 
                 iconSize = floatArrayOf(60f, 52f, 52f, 60f)
                 iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
@@ -319,7 +319,6 @@
 
                 numDatabaseHotseatIcons = 6
 
-                hotseatColumnSpan = IntArray(4) { 6 }
                 hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
                 hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
 
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index 88a430b..b813095 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -25,8 +25,6 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
-import org.junit.AfterClass
-import org.junit.BeforeClass
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -48,20 +46,6 @@
     private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
     private val launcherPrefs by lazy { LauncherPrefs.get(context) }
 
-    companion object {
-        @BeforeClass
-        @JvmStatic
-        fun setup() {
-            moveStartupDataToDeviceProtectedStorageIsEnabled = true
-        }
-
-        @AfterClass
-        @JvmStatic
-        fun teardown() {
-            moveStartupDataToDeviceProtectedStorageIsEnabled = false
-        }
-    }
-
     @Test
     fun has_keyMissingFromLauncherPrefs_returnsFalse() {
         assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
@@ -223,31 +207,12 @@
     }
 
     @Test
-    fun put_bootAwareItem_updatesEncryptedStorage() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-        encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
-
-        launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue))
-        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
-
-        launcherPrefs.removeSync(bootAwareItem)
-    }
-
-    @Test
     fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
         val bootAwareItem =
             LauncherPrefs.backedUpItem(
                 TEST_PREF_KEY,
                 TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.DEVICE_PROTECTED
             )
 
         val bootAwarePrefs: SharedPreferences =
@@ -263,90 +228,4 @@
         launcherPrefs.removeSync(bootAwareItem)
         assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
     }
-
-    @Test
-    fun remove_bootAwareItem_removesFromEncryptedStorage() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
-            .commit()
-
-        launcherPrefs.removeSync(bootAwareItem)
-        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
-    }
-
-    @Test
-    fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-        launcherPrefs.removeSync(bootAwareItem)
-
-        val bootAwarePrefs: SharedPreferences =
-            context
-                .createDeviceProtectedStorageContext()
-                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
-
-        if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) {
-            bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
-        }
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
-            .commit()
-
-        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
-        assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
-
-        launcherPrefs.removeSync(bootAwareItem)
-    }
-
-    @Test
-    fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() {
-        val onlyEncryptedItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY + "_",
-                TEST_DEFAULT_VALUE + "_",
-                EncryptionType.ENCRYPTED
-            )
-
-        val bootAwarePrefs: SharedPreferences =
-            context
-                .createDeviceProtectedStorageContext()
-                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
-
-        if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) {
-            bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
-        }
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue)
-            .commit()
-
-        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
-        assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse()
-
-        encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
-    }
 }
diff --git a/tests/src/com/android/launcher3/UtilitiesKtTest.kt b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
index dd83871..9aa0369 100644
--- a/tests/src/com/android/launcher3/UtilitiesKtTest.kt
+++ b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
@@ -20,15 +20,14 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER
 import com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER
 import com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree
 import com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree
-import com.android.launcher3.util.ActivityContextWrapper
-import com.android.launcher3.views.WidgetsEduView
+import com.android.launcher3.tests.R
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -38,17 +37,17 @@
 @RunWith(AndroidJUnit4::class)
 class UtilitiesKtTest {
 
-    val context: Context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+    val context: Context = InstrumentationRegistry.getInstrumentation().context
 
-    private lateinit var rootView: WidgetsEduView
+    private lateinit var rootView: ViewGroup
     private lateinit var midView: ViewGroup
     private lateinit var childView: View
     @Before
     fun setup() {
         rootView =
-            LayoutInflater.from(context).inflate(R.layout.widgets_edu, null) as WidgetsEduView
-        midView = rootView.requireViewById(R.id.edu_view)
-        childView = rootView.requireViewById(R.id.edu_header)
+            LayoutInflater.from(context).inflate(R.layout.utilities_test_view, null) as ViewGroup
+        midView = rootView.requireViewById(R.id.mid_view)
+        childView = rootView.requireViewById(R.id.child_view)
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
index 423ca24..d2238ff 100644
--- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -98,7 +98,7 @@
         when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
                 .thenAnswer(answer(this::addPrivateSpaceHeader));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(any()))
                 .thenReturn(iteminfo -> iteminfo.componentName == null
                         || !iteminfo.componentName.getPackageName()
                         .equals("com.android.launcher3.tests.camera"));
@@ -127,7 +127,7 @@
         when(mPrivateProfileManager.addSystemAppsDivider(any()))
                 .thenAnswer(answer(this::addSystemAppsDivider));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(mContext))
                 .thenReturn(iteminfo -> iteminfo.componentName == null
                         || !iteminfo.componentName.getPackageName()
                         .equals("com.android.launcher3.tests.camera"));
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 2dcbda4..4cd2a07 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -150,6 +151,7 @@
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
         doNothing().when(privateProfileManager).executeLock();
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(false, true);
 
@@ -165,10 +167,10 @@
     }
 
     @Test
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320703862
     public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(false);
         doNothing().when(privateProfileManager).expandPrivateSpace();
@@ -182,11 +184,11 @@
     }
 
     @Test
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
         doNothing().when(privateProfileManager).executeLock();
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(true);
         doNothing().when(privateProfileManager).expandPrivateSpace();
@@ -200,12 +202,13 @@
     }
 
     @Test
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/339109319
     public void openPrivateSpaceSettings_triggersCorrectIntent() {
         Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent();
         ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
         mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
 
-        mPrivateProfileManager.openPrivateSpaceSettings();
+        mPrivateProfileManager.openPrivateSpaceSettings(null);
 
         Mockito.verify(mContext).startActivity(acIntent.capture());
         assertEquals("Intent Action is different",
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 9363ce8..512b2ac 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -71,6 +71,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Predicate;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -279,10 +280,8 @@
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
-                .thenReturn(iteminfo -> iteminfo.componentName == null
-                        || !iteminfo.componentName.getPackageName()
-                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
         doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
         doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
                 .addPrivateSpaceHeader(any());
@@ -316,10 +315,8 @@
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
-                .thenReturn(iteminfo -> iteminfo.componentName == null
-                        || !iteminfo.componentName.getPackageName()
-                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
         doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
         doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
                 .addPrivateSpaceHeader(any());
@@ -353,10 +350,8 @@
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
-                .thenReturn(iteminfo -> iteminfo.componentName == null
-                        || !iteminfo.componentName.getPackageName()
-                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
         doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
         doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
                 .addPrivateSpaceHeader(any());
@@ -390,10 +385,8 @@
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
-                .thenReturn(iteminfo -> iteminfo.componentName == null
-                        || !iteminfo.componentName.getPackageName()
-                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
         doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
         doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
         doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
@@ -465,4 +458,10 @@
         }
         return appInfos.toArray(AppInfo[]::new);
     }
+
+    private Predicate<AppInfo> splitIntoUserInstalledAndSystemApps() {
+        return iteminfo -> iteminfo.componentName == null
+                || !iteminfo.componentName.getPackageName()
+                .equals(CAMERA_PACKAGE_NAME);
+    }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
index 389d027..28a1325 100644
--- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
+++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
@@ -40,7 +40,6 @@
 import com.android.launcher3.tapl.WidgetResizeFrame;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.ModelTestExtensions;
-import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.ShellCommandRule;
 
 import org.junit.After;
@@ -238,7 +237,6 @@
     }
 
     @Test
-    @ScreenRecordRule.ScreenRecord // b/330019521
     public void simpleReorder() throws Exception {
         runTestCaseMap(getTestMap("ReorderWidgets/simple_reorder_case"),
                 "push_reorder_case");
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index d64d096..1c41ded 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -21,8 +21,6 @@
 import static com.android.launcher3.util.TestConstants.AppNames.PHOTOS_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -43,8 +41,6 @@
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.Test;
 
@@ -67,9 +63,6 @@
      */
     @Test
     @PortraitLandscape
-    @ScreenRecord
-    // Staging; will be promoted to presubmit if stable
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @PlatinumTest(focusArea = "launcher")
     public void testDragToFolder() {
         // TODO: add the use case to drag an icon to an existing folder. Currently it either fails
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index df71ec0..362596c 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.Test;
@@ -114,7 +115,6 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/326130648
     public void testUninstallFromAllApps() throws Exception {
         installDummyAppAndWaitForUIUpdate();
         try {
@@ -132,6 +132,7 @@
      */
     @Test
     @PlatinumTest(focusArea = "launcher")
+    @ScreenRecordRule.ScreenRecord // b/319501259
     public void uninstallWorkspaceIcon() throws IOException {
         Point[] gridPositions = TestUtil.getCornersAndCenterPositions(mLauncher);
         StringBuilder sb = new StringBuilder();
@@ -162,12 +163,10 @@
             mLauncher.getWorkspace().verifyWorkspaceAppIconIsGone(
                     DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
 
-            if (!TestStabilityRule.isPresubmit()) { // b/315847371
-                Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
-                Map<String, Point> finalPositions =
-                        mLauncher.getWorkspace().getWorkspaceIconsPositions();
-                assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
-            }
+            Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
+            Map<String, Point> finalPositions =
+                    mLauncher.getWorkspace().getWorkspaceIconsPositions();
+            assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
         } finally {
             TestUtil.uninstallDummyApp();
         }
@@ -178,6 +177,8 @@
      */
     @Test
     @PortraitLandscape
+    @ScreenRecordRule.ScreenRecord // b/338869019
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/338869019
     public void testAddDeleteShortcutOnHotseat() {
         mLauncher.getWorkspace()
                 .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
index 715a1f8..7242e9c 100644
--- a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
+++ b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -30,6 +30,7 @@
 import android.view.animation.PathInterpolator;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.launcher3.CellLayout;
 
@@ -50,7 +51,8 @@
     @Mock
     CellLayout mCellLayout;
 
-    private final PreviewBackground mPreviewBackground = new PreviewBackground();
+    private final PreviewBackground mPreviewBackground =
+            new PreviewBackground(InstrumentationRegistry.getInstrumentation().getContext());
 
     @Before
     public void setUp() {
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index d3a6355..328558d 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -8,8 +8,6 @@
 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
 import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
 import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -98,7 +96,6 @@
     }
 
     @Test
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
     public void testCacheUpdate_update_apps() {
         // Run on model executor so that no other task runs in the middle.
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
@@ -129,7 +126,6 @@
     }
 
     @Test
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
     public void testSessionUpdate_updates_pending_apps() {
         // Run on model executor so that no other task runs in the middle.
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 2e209a4..c4a4c9b 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -24,13 +24,11 @@
 import com.android.launcher3.util.LauncherModelHelper
 import com.android.launcher3.util.LauncherModelHelper.*
 import com.android.launcher3.util.TestUtil
-import com.android.launcher3.util.rule.TestStabilityRule
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.CountDownLatch
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -58,8 +56,6 @@
             TEST_ACTIVITY14
         )
 
-    @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
-
     @Before
     fun setUp() {
         modelHelper = LauncherModelHelper()
@@ -91,9 +87,6 @@
 
     @Test
     @Throws(Exception::class)
-    @TestStabilityRule.Stability(
-        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
-    ) // b/319923578
     fun folderLoadedWithHighRes_max_3x3() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(3, 3, 3, 3)
@@ -107,9 +100,6 @@
 
     @Test
     @Throws(Exception::class)
-    @TestStabilityRule.Stability(
-        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
-    ) // b/319923578
     fun folderLoadedWithHighRes_max_4x4() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(4, 4, 4, 4)
@@ -123,10 +113,6 @@
 
     @Test
     @Throws(Exception::class)
-    // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
-    @TestStabilityRule.Stability(
-        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
-    ) // b/319923578
     fun folderLoadedWithHighRes_differentFolderConfigurations() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(4, 3, 4, 4)
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 56ac960..b4945d7 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -79,6 +79,7 @@
 
     private LauncherModelHelper mModelHelper;
     private LauncherAppState mApp;
+    private PackageManagerHelper mPmHelper;
 
     private MatrixCursor mCursor;
     private InvariantDeviceProfile mIDP;
@@ -92,6 +93,7 @@
         mContext = mModelHelper.sandboxContext;
         mIDP = InvariantDeviceProfile.INSTANCE.get(mContext);
         mApp = LauncherAppState.getInstance(mContext);
+        mPmHelper = PackageManagerHelper.INSTANCE.get(mContext);
 
         mCursor = new MatrixCursor(new String[] {
                 ICON, TITLE, _ID, CONTAINER, ITEM_TYPE,
@@ -101,7 +103,7 @@
         });
 
         UserManagerState ums = new UserManagerState();
-        mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, null);
+        mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, mPmHelper, null);
         ums.allUsers.put(0, Process.myUserHandle());
     }
 
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 5731e2a..28a001f 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -56,7 +56,7 @@
 
     @Spy private var userManagerState: UserManagerState? = UserManagerState()
 
-    @get:Rule val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     @Before
     fun setup() {
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 30957fc..6bbcf85 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -24,28 +24,44 @@
 import android.content.pm.PackageInstaller
 import android.content.pm.ShortcutInfo
 import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
 import android.util.LongSparseArray
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
 import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_WIDGET_PROVIDER
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.PROFILE_DELETED
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
 import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.UserCache
 import com.android.launcher3.shortcuts.ShortcutKey
 import com.android.launcher3.util.ComponentKey
 import com.android.launcher3.util.PackageManagerHelper
 import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.UserIconInfo
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
 import com.android.launcher3.widget.WidgetInflater
+import com.android.launcher3.widget.WidgetSections
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
 import org.junit.Test
+import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.RETURNS_DEEP_STUBS
 import org.mockito.Mockito.mock
@@ -54,8 +70,10 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
 
 class WorkspaceItemProcessorTest {
 
@@ -64,37 +82,40 @@
     @Mock private lateinit var mockBgDataModel: BgDataModel
     @Mock private lateinit var mockContext: Context
     @Mock private lateinit var mockAppState: LauncherAppState
-    @Mock private lateinit var mockIntent: Intent
     @Mock private lateinit var mockPmHelper: PackageManagerHelper
     @Mock private lateinit var mockLauncherApps: LauncherApps
     @Mock private lateinit var mockCursor: LoaderCursor
+    @Mock private lateinit var mockUserCache: UserCache
     @Mock private lateinit var mockUserManagerState: UserManagerState
     @Mock private lateinit var mockWidgetInflater: WidgetInflater
 
-    private lateinit var userHandle: UserHandle
-    private lateinit var iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>
-    private lateinit var componentName: ComponentName
-    private lateinit var unlockedUsersArray: LongSparseArray<Boolean>
-    private lateinit var keyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo>
-    private lateinit var installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>
-    private lateinit var allDeepShortcuts: MutableList<ShortcutInfo>
+    private var intent: Intent = Intent()
+    private var mUserHandle: UserHandle = UserHandle(0)
+    private var mIconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf()
+    private var mComponentName: ComponentName = ComponentName("package", "class")
+    private var mUnlockedUsersArray: LongSparseArray<Boolean> = LongSparseArray()
+    private var mKeyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo> = mutableMapOf()
+    private var mInstallingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf()
+    private var mAllDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+    private var mWidgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> =
+        mutableMapOf()
+    private var mPendingPackages: MutableSet<PackageUserKey> = mutableSetOf()
 
     private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
 
     @Before
     fun setup() {
-        userHandle = UserHandle(0)
+        mUserHandle = UserHandle(0)
         mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
-        iconRequestInfos = mutableListOf(mockIconRequestInfo)
         mockWorkspaceInfo = mock<WorkspaceItemInfo>()
         mockBgDataModel = mock<BgDataModel>()
-        componentName = ComponentName("package", "class")
-        unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
-        mockIntent =
-            mock<Intent>().apply {
-                whenever(component).thenReturn(componentName)
-                whenever(`package`).thenReturn("pkg")
-                whenever(getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)).thenReturn("")
+        mComponentName = ComponentName("package", "class")
+        mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+        intent =
+            Intent().apply {
+                component = mComponentName
+                `package` = "pkg"
+                putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
             }
         mockContext =
             mock<Context>().apply {
@@ -109,34 +130,43 @@
             }
         mockPmHelper =
             mock<PackageManagerHelper>().apply {
-                whenever(getAppLaunchIntent(componentName.packageName, userHandle))
-                    .thenReturn(mockIntent)
+                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+                    .thenReturn(intent)
             }
         mockLauncherApps =
             mock<LauncherApps>().apply {
-                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
-                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(true)
+                whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+                whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
             }
         mockCursor =
             mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
-                user = userHandle
+                user = mUserHandle
                 itemType = ITEM_TYPE_APPLICATION
                 id = 1
                 restoreFlag = 1
                 serialNumber = 101
-                whenever(parseIntent()).thenReturn(mockIntent)
+                whenever(parseIntent()).thenReturn(intent)
                 whenever(markRestored()).doAnswer { restoreFlag = 0 }
-                whenever(updater().put(Favorites.INTENT, mockIntent.toUri(0)).commit())
-                    .thenReturn(1)
+                whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
                 whenever(getAppShortcutInfo(any(), any(), any(), any()))
                     .thenReturn(mockWorkspaceInfo)
                 whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
             }
+        mockUserCache =
+            mock<UserCache>().apply {
+                val userIconInfo =
+                    mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
+                whenever(getUserInfo(any())).thenReturn(userIconInfo)
+            }
+
         mockUserManagerState = mock<UserManagerState>()
         mockWidgetInflater = mock<WidgetInflater>()
-        keyToPinnedShortcutsMap = mutableMapOf()
-        installingPkgs = hashMapOf()
-        allDeepShortcuts = mutableListOf()
+        mKeyToPinnedShortcutsMap = mutableMapOf()
+        mInstallingPkgs = hashMapOf()
+        mAllDeepShortcuts = mutableListOf()
+        mWidgetProvidersMap = mutableMapOf()
+        mIconRequestInfos = mutableListOf()
+        mPendingPackages = mutableSetOf()
     }
 
     /**
@@ -147,24 +177,26 @@
     private fun createWorkspaceItemProcessorUnderTest(
         cursor: LoaderCursor = mockCursor,
         memoryLogger: LoaderMemoryLogger? = null,
+        userCache: UserCache = mockUserCache,
         userManagerState: UserManagerState = mockUserManagerState,
         launcherApps: LauncherApps = mockLauncherApps,
-        shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = keyToPinnedShortcutsMap,
+        shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
         app: LauncherAppState = mockAppState,
         bgDataModel: BgDataModel = mockBgDataModel,
-        widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mutableMapOf(),
+        widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
         widgetInflater: WidgetInflater = mockWidgetInflater,
         pmHelper: PackageManagerHelper = mockPmHelper,
-        iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf(),
+        iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mIconRequestInfos,
         isSdCardReady: Boolean = false,
-        pendingPackages: MutableSet<PackageUserKey> = mutableSetOf(),
-        unlockedUsers: LongSparseArray<Boolean> = unlockedUsersArray,
-        installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf(),
-        allDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+        pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
+        unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
+        installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
+        allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
     ) =
         WorkspaceItemProcessor(
             c = cursor,
             memoryLogger = memoryLogger,
+            userCache = userCache,
             userManagerState = userManagerState,
             launcherApps = launcherApps,
             app = app,
@@ -185,9 +217,11 @@
     fun `When user is null then mark item deleted`() {
         // Given
         mockCursor = mock<LoaderCursor>().apply { id = 1 }
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
+
         // Then
         verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
         verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
@@ -197,8 +231,9 @@
     fun `When app has null intent then mark deleted`() {
         // Given
         mockCursor.apply { whenever(parseIntent()).thenReturn(null) }
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
         // Then
         verify(mockCursor).markDeleted("Null intent from db for item id=1", MISSING_INFO)
@@ -209,13 +244,13 @@
     fun `When app has null target package then mark deleted`() {
 
         // Given
-        mockIntent.apply {
-            whenever(component).thenReturn(null)
-            whenever(`package`).thenReturn(null)
+        intent.apply {
+            component = null
+            `package` = null
         }
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
 
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
@@ -227,12 +262,12 @@
     fun `When app has empty String target package then mark deleted`() {
 
         // Given
-        componentName = ComponentName("", "")
-        whenever(mockIntent.component).thenReturn(componentName)
-        whenever(mockCursor.parseIntent()).thenReturn(mockIntent)
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        mComponentName = ComponentName("", "")
+        intent.component = mComponentName
+        intent.`package` = ""
 
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
@@ -243,10 +278,8 @@
     @Test
     fun `When valid app then mark restored`() {
 
-        // Given
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
-
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
@@ -255,7 +288,7 @@
             .isEqualTo(0)
         // currently gets marked restored twice, although markRestore() has check for restoreFlag
         verify(mockCursor, times(2)).markRestored()
-        assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+        assertThat(mIconRequestInfos).containsExactly(mockIconRequestInfo)
         verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
     }
 
@@ -265,25 +298,25 @@
         // Given
         mockLauncherApps =
             mock<LauncherApps>().apply {
-                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
-                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+                whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+                whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(false)
             }
         mockPmHelper =
             mock<PackageManagerHelper>().apply {
-                whenever(getAppLaunchIntent(componentName.packageName, userHandle))
-                    .thenReturn(mockIntent)
+                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+                    .thenReturn(intent)
             }
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
 
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
         assertWithMessage("item restoreFlag should be set to 0")
             .that(mockCursor.restoreFlag)
             .isEqualTo(0)
-        verify(mockCursor.updater().put(Favorites.INTENT, mockIntent.toUri(0))).commit()
-        assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+        verify(mockCursor.updater().put(Favorites.INTENT, intent.toUri(0))).commit()
+        assertThat(mIconRequestInfos).containsExactly(mockIconRequestInfo)
         verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
     }
 
@@ -293,16 +326,17 @@
         // Given
         mockLauncherApps =
             mock<LauncherApps>().apply {
-                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
-                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+                whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+                whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(false)
             }
         mockPmHelper =
             mock<PackageManagerHelper>().apply {
-                whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
+                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+                    .thenReturn(null)
             }
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
 
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
@@ -336,21 +370,21 @@
                 whenever(disabledReason).thenReturn(0)
                 whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
             }
-        val shortcutKey = ShortcutKey.fromIntent(mockIntent, mockCursor.user)
-        keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
-        iconRequestInfos = mutableListOf()
-        itemProcessorUnderTest =
-            createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+        val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+        mKeyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+        mIconRequestInfos = mutableListOf()
 
         // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(allDeepShortcuts = mAllDeepShortcuts)
         itemProcessorUnderTest.processItem()
 
         // Then
         assertWithMessage("item restoreFlag should be set to 0")
             .that(mockCursor.restoreFlag)
             .isEqualTo(0)
-        assertThat(iconRequestInfos).isEmpty()
-        assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+        assertThat(mIconRequestInfos).isEmpty()
+        assertThat(mAllDeepShortcuts).containsExactly(expectedShortcutInfo)
         verify(mockCursor).markRestored()
         verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
     }
@@ -360,18 +394,18 @@
 
         // Given
         mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
-        iconRequestInfos = mutableListOf()
-        keyToPinnedShortcutsMap = hashMapOf()
-        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        mIconRequestInfos = mutableListOf()
+        mKeyToPinnedShortcutsMap = hashMapOf()
 
         // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
         itemProcessorUnderTest.processItem()
 
         // Then
         assertWithMessage("item restoreFlag should be set to 0")
             .that(mockCursor.restoreFlag)
             .isEqualTo(0)
-        assertThat(iconRequestInfos).isEmpty()
+        assertThat(mIconRequestInfos).isEmpty()
         verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
         verify(mockCursor)
             .markDeleted(
@@ -381,6 +415,45 @@
     }
 
     @Test
+    fun `When valid Pinned Deep Shortcut with null intent package then use targetPkg`() {
+
+        // Given
+        mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+        val expectedShortcutInfo =
+            mock<ShortcutInfo>().apply {
+                whenever(id).thenReturn("")
+                whenever(`package`).thenReturn("")
+                whenever(activity).thenReturn(mock())
+                whenever(longLabel).thenReturn("")
+                whenever(isEnabled).thenReturn(true)
+                whenever(disabledMessage).thenReturn("")
+                whenever(disabledReason).thenReturn(0)
+                whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+            }
+        mIconRequestInfos = mutableListOf()
+        // Make sure shortcuts map has expected key from expected package
+        intent.`package` = mComponentName.packageName
+        val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+        mKeyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+        // set intent package back to null to test scenario
+        intent.`package` = null
+
+        // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(allDeepShortcuts = mAllDeepShortcuts)
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        assertThat(mIconRequestInfos).isEmpty()
+        assertThat(mAllDeepShortcuts).containsExactly(expectedShortcutInfo)
+        verify(mockCursor).markRestored()
+        verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
     fun `When processing Folder then create FolderInfo and mark restored`() {
         val actualFolderInfo = FolderInfo()
         mockBgDataModel =
@@ -427,4 +500,346 @@
         assertThat(actualFolderInfo.options).isEqualTo(expectedFolderInfo.options)
         verify(mockCursor).checkAndAddItem(actualFolderInfo, mockBgDataModel, null)
     }
+
+    @Test
+    fun `When valid TYPE_REAL App Widget then add item`() {
+
+        // Given
+        val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+        val expectedComponentName =
+            ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+        val expectedRestoreStatus = FLAG_UI_NOT_READY
+        val expectedAppWidgetId = 0
+        mockCursor.apply {
+            itemType = ITEM_TYPE_APPWIDGET
+            user = mUserHandle
+            restoreFlag = FLAG_UI_NOT_READY
+            container = CONTAINER_DESKTOP
+            whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+            whenever(appWidgetProvider).thenReturn(expectedProvider)
+            whenever(appWidgetId).thenReturn(expectedAppWidgetId)
+            whenever(spanX).thenReturn(2)
+            whenever(spanY).thenReturn(1)
+            whenever(options).thenReturn(0)
+            whenever(appWidgetSource).thenReturn(20)
+            whenever(applyCommonProperties(any())).thenCallRealMethod()
+            whenever(
+                    updater()
+                        .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
+                        .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+                        .put(Favorites.RESTORED, expectedRestoreStatus)
+                        .commit()
+                )
+                .thenReturn(1)
+        }
+        val expectedWidgetInfo =
+            LauncherAppWidgetInfo().apply {
+                appWidgetId = expectedAppWidgetId
+                providerName = ComponentName.unflattenFromString(expectedProvider)
+                restoreStatus = expectedRestoreStatus
+            }
+        val expectedWidgetProviderInfo =
+            mock<LauncherAppWidgetProviderInfo>().apply {
+                provider = ComponentName.unflattenFromString(expectedProvider)
+                whenever(user).thenReturn(mUserHandle)
+            }
+        val inflationResult =
+            WidgetInflater.InflationResult(
+                type = WidgetInflater.TYPE_REAL,
+                widgetInfo = expectedWidgetProviderInfo
+            )
+        mockWidgetInflater =
+            mock<WidgetInflater>().apply {
+                whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+            }
+        val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
+        mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
+
+        // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
+        verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
+        val actualWidgetInfo = widgetInfoCaptor.value
+        with(actualWidgetInfo) {
+            assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
+            assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
+            assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
+            assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
+        }
+        val expectedComponentKey =
+            ComponentKey(expectedWidgetProviderInfo.provider, expectedWidgetProviderInfo.user)
+        assertThat(mWidgetProvidersMap[expectedComponentKey]).isEqualTo(expectedWidgetProviderInfo)
+    }
+
+    @Test
+    fun `When valid Pending Widget then checkAndAddItem`() {
+
+        // Given
+        mockCursor =
+            mock<LoaderCursor>().apply {
+                itemType = ITEM_TYPE_APPWIDGET
+                id = 1
+                user = UserHandle(1)
+                restoreFlag = FLAG_UI_NOT_READY
+                container = CONTAINER_DESKTOP
+                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                whenever(appWidgetProvider)
+                    .thenReturn("com.google.android.testApp/com.android.testApp.testAppProvider")
+                whenever(appWidgetId).thenReturn(0)
+                whenever(spanX).thenReturn(2)
+                whenever(spanY).thenReturn(1)
+                whenever(options).thenReturn(0)
+                whenever(appWidgetSource).thenReturn(20)
+                whenever(applyCommonProperties(any())).thenCallRealMethod()
+            }
+        val mockProviderInfo =
+            mock<LauncherAppWidgetProviderInfo>().apply {
+                provider = mock()
+                whenever(user).thenReturn(UserHandle(1))
+            }
+        val inflationResult =
+            WidgetInflater.InflationResult(
+                type = WidgetInflater.TYPE_PENDING,
+                widgetInfo = mockProviderInfo
+            )
+        mockWidgetInflater =
+            mock<WidgetInflater>().apply {
+                whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+            }
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+        // When
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor).checkAndAddItem(any(), any())
+    }
+
+    @Test
+    fun `When Unrestored Pending App Widget then mark deleted`() {
+
+        // Given
+        val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+        mockCursor =
+            mock<LoaderCursor>().apply {
+                itemType = ITEM_TYPE_APPWIDGET
+                id = 1
+                user = UserHandle(1)
+                restoreFlag = FLAG_UI_NOT_READY
+                container = CONTAINER_DESKTOP
+                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                whenever(appWidgetProvider).thenReturn(expectedProvider)
+                whenever(appWidgetId).thenReturn(0)
+                whenever(spanX).thenReturn(2)
+                whenever(spanY).thenReturn(1)
+                whenever(options).thenReturn(0)
+                whenever(appWidgetSource).thenReturn(20)
+                whenever(applyCommonProperties(any())).thenCallRealMethod()
+            }
+        mInstallingPkgs = hashMapOf()
+        val inflationResult =
+            WidgetInflater.InflationResult(type = WidgetInflater.TYPE_PENDING, widgetInfo = null)
+        mockWidgetInflater =
+            mock<WidgetInflater>().apply {
+                whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+            }
+        val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+
+        // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor)
+            .markDeleted(
+                "processWidget: Unrestored Pending widget removed: id=1, appWidgetId=0, component=$expectedComponentName, restoreFlag:=4",
+                LauncherRestoreEventLogger.RestoreError.APP_NOT_INSTALLED
+            )
+    }
+
+    @Test
+    fun `When Pending App Widget has not started restore then update db and add item`() {
+
+        val mockitoSession =
+            ExtendedMockito.mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .mockStatic(WidgetSections::class.java)
+                .startMocking()
+        try {
+            // Given
+            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+            val expectedComponentName =
+                ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+            val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
+            val expectedAppWidgetId = 0
+            mockCursor.apply {
+                itemType = ITEM_TYPE_APPWIDGET
+                user = mUserHandle
+                restoreFlag = FLAG_UI_NOT_READY
+                container = CONTAINER_DESKTOP
+                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                whenever(appWidgetProvider).thenReturn(expectedProvider)
+                whenever(appWidgetId).thenReturn(expectedAppWidgetId)
+                whenever(spanX).thenReturn(2)
+                whenever(spanY).thenReturn(1)
+                whenever(options).thenReturn(0)
+                whenever(appWidgetSource).thenReturn(20)
+                whenever(applyCommonProperties(any())).thenCallRealMethod()
+                whenever(
+                        updater()
+                            .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
+                            .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+                            .put(Favorites.RESTORED, expectedRestoreStatus)
+                            .commit()
+                    )
+                    .thenReturn(1)
+            }
+            val inflationResult =
+                WidgetInflater.InflationResult(
+                    type = WidgetInflater.TYPE_PENDING,
+                    widgetInfo = null
+                )
+            mockWidgetInflater =
+                mock<WidgetInflater>().apply {
+                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+                }
+            val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
+            mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
+
+            // When
+            itemProcessorUnderTest =
+                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+            itemProcessorUnderTest.processItem()
+
+            // Then
+            val expectedWidgetInfo =
+                LauncherAppWidgetInfo().apply {
+                    appWidgetId = expectedAppWidgetId
+                    providerName = ComponentName.unflattenFromString(expectedProvider)
+                    restoreStatus = expectedRestoreStatus
+                }
+            verify(
+                    mockCursor
+                        .updater()
+                        .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
+                        .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+                        .put(Favorites.RESTORED, expectedRestoreStatus)
+                )
+                .commit()
+            val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
+            verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
+            val actualWidgetInfo = widgetInfoCaptor.value
+            with(actualWidgetInfo) {
+                assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
+                assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
+                assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
+                assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
+            }
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    fun `When Archived Pending App Widget then checkAndAddItem`() {
+        val mockitoSession =
+            ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
+        try {
+            // Given
+            val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+            val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+            val expectedPackage = expectedComponentName!!.packageName
+            mockPmHelper =
+                mock<PackageManagerHelper>().apply {
+                    whenever(isAppArchived(expectedPackage)).thenReturn(true)
+                }
+            mockCursor =
+                mock<LoaderCursor>().apply {
+                    itemType = ITEM_TYPE_APPWIDGET
+                    id = 1
+                    user = UserHandle(1)
+                    restoreFlag = FLAG_UI_NOT_READY
+                    container = CONTAINER_DESKTOP
+                    whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                    whenever(appWidgetProvider).thenReturn(expectedProvider)
+                    whenever(appWidgetId).thenReturn(0)
+                    whenever(spanX).thenReturn(2)
+                    whenever(spanY).thenReturn(1)
+                    whenever(options).thenReturn(0)
+                    whenever(appWidgetSource).thenReturn(20)
+                    whenever(applyCommonProperties(any())).thenCallRealMethod()
+                }
+            mInstallingPkgs = hashMapOf()
+            val inflationResult =
+                WidgetInflater.InflationResult(
+                    type = WidgetInflater.TYPE_PENDING,
+                    widgetInfo = null
+                )
+            mockWidgetInflater =
+                mock<WidgetInflater>().apply {
+                    whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+                }
+            itemProcessorUnderTest =
+                createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+            // When
+            itemProcessorUnderTest.processItem()
+
+            // Then
+            verify(mockCursor).checkAndAddItem(any(), any())
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    @Test
+    fun `When widget inflation result is TYPE_DELETE then mark deleted`() {
+        // Given
+        val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+        val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+        val expectedPackage = expectedComponentName!!.packageName
+        mockPmHelper =
+            mock<PackageManagerHelper>().apply {
+                whenever(isAppArchived(expectedPackage)).thenReturn(true)
+            }
+        mockCursor =
+            mock<LoaderCursor>().apply {
+                itemType = ITEM_TYPE_APPWIDGET
+                id = 1
+                user = UserHandle(1)
+                container = CONTAINER_DESKTOP
+                whenever(spanX).thenReturn(2)
+                whenever(spanY).thenReturn(1)
+                whenever(appWidgetProvider).thenReturn(expectedProvider)
+                whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+                whenever(applyCommonProperties(any())).thenCallRealMethod()
+            }
+        mInstallingPkgs = hashMapOf()
+        val inflationResult =
+            WidgetInflater.InflationResult(
+                type = WidgetInflater.TYPE_DELETE,
+                widgetInfo = null,
+                reason = "test_delete_reason",
+                restoreErrorType = MISSING_WIDGET_PROVIDER
+            )
+        mockWidgetInflater =
+            mock<WidgetInflater>().apply {
+                whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+            }
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+        // When
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor).markDeleted(inflationResult.reason, inflationResult.restoreErrorType)
+    }
 }
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index 9912a34..408691c 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -42,6 +42,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(145)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1445)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(177)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(177)
@@ -64,6 +66,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(72)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1080)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(110)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(110)
@@ -85,6 +89,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(104)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1468)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(370)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(370)
@@ -100,22 +106,21 @@
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
-        inv?.apply {
-            hotseatColumnSpan = IntArray(4) { 4 }
-            inlineQsb = BooleanArray(4) { false }
-        }
+        inv?.apply { inlineQsb = BooleanArray(4) { false } }
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(100)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(248)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1960)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(668)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(668)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(300)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1214)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1950)
     }
 
     /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@@ -128,13 +133,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(91)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(233)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1885)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(640)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(640)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(287)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(287)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1169)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1875)
     }
 
     /**
@@ -150,13 +157,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(75)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(205)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1745)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(582)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(582)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(257)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(257)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1085)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1735)
     }
 
     @Test
@@ -179,4 +188,23 @@
             assertThat(dp.hotseatQsbWidth).isEqualTo(1435)
         }
     }
+
+    @Test
+    fun increase_span_when_space_between_icons_is_less_than_minimum() {
+        initializeVarsForTwoPanel(isGestureMode = false, isLandscape = false, rows = 5, cols = 5)
+        val dp = newDP()
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(112)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(8)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1383)
+
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(228)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(228)
+
+        assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1372)
+    }
 }
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index e459956..dc8c17a 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -30,6 +30,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -244,7 +245,6 @@
         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
                 .getShortcut(mTestContext, mAppInfo, mView);
 
-        verify(mPrivateProfileManager, times(2)).getProfileUser();
         assertNull(systemShortcut);
     }
 
@@ -266,8 +266,7 @@
         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
                 .getShortcut(mTestContext, mAppInfo, mView);
 
-        verify(mPrivateProfileManager, times(3)).getProfileUser();
-        verify(mPrivateProfileManager).isEnabled();
+        verify(mPrivateProfileManager, atLeast(1)).isEnabled();
         assertNotNull(systemShortcut);
     }
 
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 99e15ba..115a6e6 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -98,7 +98,7 @@
 public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher> {
 
     public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
-    public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
+    public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 10;
 
     public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT;
     private static final String TAG = "AbstractLauncherUiTest";
@@ -548,7 +548,7 @@
         public Intent blockingGetIntent() throws InterruptedException {
             Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
                     "AbstractLauncherUiTest.blockingGetIntent()");
-            latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
+            assertTrue("Timed Out", latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS));
             mTargetContext.unregisterReceiver(this);
             Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, mIntent == null
                     ? "AbstractLauncherUiTest.onReceive(): mIntent NULL"
diff --git a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
index 3411fc1..e49f2b1 100644
--- a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
+++ b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
@@ -69,13 +69,7 @@
     private WorkProfileManager mWorkManager;
     private Context mContext;
 
-    @Rule public final SetFlagsRule mSetFlagsRule = getFlagsRule();
-
-    private SetFlagsRule getFlagsRule() {
-        SetFlagsRule flagsRule = new SetFlagsRule();
-        flagsRule.initAllFlagsToReleaseConfigDefault();
-        return flagsRule;
-    }
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Before
     public void setUp() {
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index c4e74f2..e5c5c19 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -57,7 +57,7 @@
                                         true));
 
                     } catch (Throwable e) {
-                        FailureWatcher.onError(mTest.mLauncher, description, e);
+                        FailureWatcher.onError(mTest.mLauncher, description);
                         throw e;
                     }
 
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
index 342eedf..4a67600 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
@@ -21,8 +21,9 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,6 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 public class TaplTestsLauncher3Test extends AbstractLauncherUiTest<Launcher> {
 
+    @KeepRecordOnSuccess
     @ScreenRecord // b/322823478
     @Test
     public void testDevicePressMenu() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index e08d37c..70a3dd0 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.allapps.WorkProfileManager;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 
@@ -196,6 +197,7 @@
 
     }
 
+    @KeepRecordOnSuccess
     @ScreenRecord // b/322823478
     @Test
     public void testEdu() {
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 7845dec..9dbd866 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -86,7 +86,6 @@
      * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it.
      * Custom shortcuts are replaced by deep shortcuts after api 25.
      */
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     @PortraitLandscape
     public void testDragCustomShortcut() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
index 79724e1..19c5850 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.ui.widget;
 
-import static com.android.launcher3.util.rule.ShellCommandRule.createEnableInputTransportPublisherRule;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -32,9 +30,7 @@
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
 
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 /**
@@ -44,9 +40,6 @@
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class TaplWidgetPickerTest extends AbstractLauncherUiTest<Launcher> {
-    // b/325377690 : To get the log printed where DOWN key event is getting lost from TAPL.
-    @Rule public final TestRule mEnableInputTransportPublisherRule =
-            createEnableInputTransportPublisherRule();
 
     private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
         return WidgetsFullSheet.getWidgetsView(launcher);
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index 2ce8eef..a672c01 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -20,6 +20,8 @@
 import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.MESSAGES_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -38,6 +40,7 @@
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.ScreenRecordRule;
+import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -242,6 +245,7 @@
     }
 
     @ScreenRecordRule.ScreenRecord // b/329935119
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/329935119
     @Test
     @PortraitLandscape
     public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
index 9afde0d..490cff2 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 
 import org.junit.After;
 import org.junit.Before;
@@ -67,6 +68,7 @@
      * move between workspaces. After, make sure we can launch an app from the Workspace.
      * @throws Exception if we can't set the defaults icons that will appear at the beginning.
      */
+    @ScreenRecord // b/331261431
     @Test
     public void testWorkspace() throws Exception {
         // Set workspace  that includes the chrome Activity app icon on the hotseat.
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 706ab27..273f0c4 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
 import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
 import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
 import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING
@@ -45,6 +46,7 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
@@ -93,6 +95,7 @@
         whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy)
         whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs)
         whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
+        whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
 
         // Mock WindowManagerProxy
         val displayInfo = CachedDisplayInfo(Point(width, height), Surface.ROTATION_0)
@@ -123,6 +126,7 @@
         whenever(displayManager.getDisplay(any())).thenReturn(display)
 
         // Mock resources
+        doReturn(context).whenever(context).applicationContext
         whenever(resources.configuration).thenReturn(configuration)
         whenever(context.resources).thenReturn(resources)
 
@@ -168,4 +172,13 @@
         verify(displayInfoChangeListener)
             .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
     }
+
+    @Test
+    @UiThreadTest
+    fun testTaskbarPinningChangeInDesktopMode() {
+        whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false)
+        displayController.handleInfoChange(display)
+        verify(displayInfoChangeListener)
+            .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
+    }
 }
diff --git a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
index d1da5f4..b5e797e 100644
--- a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
+++ b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
@@ -34,6 +34,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -63,6 +64,8 @@
         mContext = mock(Context.class);
         mLauncherApps = mock(LauncherApps.class);
         when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps);
+        when(mContext.getResources()).thenReturn(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getResources());
         mPackageManagerHelper = new PackageManagerHelper(mContext);
     }
 
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 7fba33e..7bdc040 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -30,6 +30,8 @@
 public class FailureWatcher extends TestWatcher {
     private static final String TAG = "FailureWatcher";
     private static boolean sSavedBugreport = false;
+    private static Description sDescriptionForLastSavedArtifacts;
+
     private final LauncherInstrumentation mLauncher;
     @NonNull
     private final Supplier<ExportedData> mViewCaptureDataSupplier;
@@ -41,6 +43,18 @@
     }
 
     @Override
+    protected void starting(Description description) {
+        mLauncher.setOnFailure(() -> onError(mLauncher, description, mViewCaptureDataSupplier));
+        super.starting(description);
+    }
+
+    @Override
+    protected void finished(Description description) {
+        super.finished(description);
+        mLauncher.setOnFailure(null);
+    }
+
+    @Override
     protected void succeeded(Description description) {
         super.succeeded(description);
         AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
@@ -70,7 +84,7 @@
 
     @Override
     protected void failed(Throwable e, Description description) {
-        onError(mLauncher, description, e, mViewCaptureDataSupplier);
+        onError(mLauncher, description, mViewCaptureDataSupplier);
     }
 
     static File diagFile(Description description, String prefix, String ext) {
@@ -79,13 +93,18 @@
                         + description.getMethodName() + "." + ext);
     }
 
-    public static void onError(LauncherInstrumentation launcher, Description description,
-            Throwable e) {
-        onError(launcher, description, e, null);
+    /** Action executed when an error condition is expected. Saves artifacts. */
+    public static void onError(LauncherInstrumentation launcher, Description description) {
+        onError(launcher, description, null);
     }
 
     private static void onError(LauncherInstrumentation launcher, Description description,
-            Throwable e, @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+            @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+        if (description.equals(sDescriptionForLastSavedArtifacts)) {
+            // This test has already saved its artifacts.
+            return;
+        }
+        sDescriptionForLastSavedArtifacts = description;
 
         final File sceenshot = diagFile(description, "TestScreenshot", "png");
         final File hierarchy = diagFile(description, "Hierarchy", "zip");
@@ -114,7 +133,7 @@
         Log.e(TAG, "Failed test " + description.getMethodName()
                 + ",\nscreenshot will be saved to " + sceenshot
                 + ",\nUI dump at: " + hierarchy
-                + " (use go/web-hv to open the dump file)", e);
+                + " (use go/web-hv to open the dump file)");
         final UiDevice device = launcher.getDevice();
         device.takeScreenshot(sceenshot);
 
diff --git a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
index 7a5cf2c..ff96afb 100644
--- a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
@@ -49,6 +49,9 @@
             return base;
         }
 
+        final Boolean keepRecordOnSuccess = description.getAnnotation(KeepRecordOnSuccess.class)
+                != null;
+
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
@@ -70,7 +73,7 @@
                     device.executeShellCommand("kill -INT " + screenRecordPid);
                     Log.e(TAG, "Screenrecord captured at: " + outputFile);
                     output.close();
-                    if (success) {
+                    if (success && !keepRecordOnSuccess) {
                         automation.executeShellCommand("rm " + outputFile);
                     }
                 }
@@ -85,4 +88,14 @@
     @Target(ElementType.METHOD)
     public @interface ScreenRecord {
     }
+
+
+    /**
+     * Interface to indicate that we should keep the screen record even if the test succeeds, use
+     * sparingly since it uses a lof of memory.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface KeepRecordOnSuccess {
+    }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/SetPropRule.java b/tests/src/com/android/launcher3/util/rule/SetPropRule.java
new file mode 100644
index 0000000..74fec35
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/SetPropRule.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rule;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiDevice;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Test rule which executes a set prop command at the start of the test.
+ * This rule needs the property tag and property value so that value can be set to a tag.
+ */
+public class SetPropRule implements TestRule {
+    private static final String SETPROP_PREFIX = "setprop";
+    private static final String GETPROP_PREFIX = "getprop";
+    private static final String UNKNOWN = "UNKNOWN";
+    @NonNull private final String mPropTag;
+    @NonNull private final String mPropValue;
+
+    public SetPropRule(@NonNull String propTag, @NonNull String propValue) {
+        mPropTag = propTag.trim();
+        mPropValue = propValue.trim();
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                String getpropCmd = GETPROP_PREFIX + " " + mPropTag;
+                String initialValue = UiDevice.getInstance(getInstrumentation())
+                        .executeShellCommand(getpropCmd);
+                if (TextUtils.isEmpty(initialValue.trim())) {
+                    initialValue = UNKNOWN;
+                }
+                // setprop command always follows format : setprop <TAG> <value>
+                String revertSetPropCmd = SETPROP_PREFIX + " " + mPropTag + " " + initialValue;
+                String setPropCmd = SETPROP_PREFIX + " " + mPropTag + " " + mPropValue;
+                new ShellCommandRule(setPropCmd, revertSetPropCmd)
+                        .apply(base, description).evaluate();
+            }
+        };
+    }
+
+    /**
+     * Enables "InputTransportPublisher" debug flag. This prints the key input events dispatched by
+     * the system server.
+     * adb shell setprop log.tag.InputTransportPublisher DEBUG
+     * See {@link com.android.cts.input.DebugInputRule} for more details.
+     */
+    public static SetPropRule createEnableInputTransportPublisherRule() {
+        return new SetPropRule("log.tag.InputTransportPublisher", "DEBUG");
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index 977995e..2219003 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -15,13 +15,12 @@
  */
 package com.android.launcher3.util.rule;
 
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
 
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
-import android.text.TextUtils;
 
 import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
@@ -40,10 +39,6 @@
  * Test rule which executes a shell command at the start of the test.
  */
 public class ShellCommandRule implements TestRule {
-
-    private static final String SETPROP_PREFIX = "setprop";
-    private static final String GETPROP_PREFIX = "getprop";
-    private static final String UNKNOWN = "UNKNOWN";
     private final String mCmd;
     private final String mRevertCommand;
     private final boolean mCheckSuccess;
@@ -66,19 +61,6 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                String revertSetPropCmd = null;
-                if (mCmd.startsWith(SETPROP_PREFIX) && mRevertCommand == null) {
-                    // setprop command always follows format : setprop <TAG> <value>
-                    // We are stripping out only the TAG here
-                    String tag = mCmd.split("\\s")[1];
-                    String getpropCmd = GETPROP_PREFIX + " " + tag;
-                    String initialValue = UiDevice.getInstance(
-                            getInstrumentation()).executeShellCommand(getpropCmd);
-                    if (TextUtils.isEmpty(initialValue.trim())) {
-                        initialValue = UNKNOWN;
-                    }
-                    revertSetPropCmd = SETPROP_PREFIX + " " + tag + " " + initialValue;
-                }
                 final String result =
                         UiDevice.getInstance(getInstrumentation()).executeShellCommand(mCmd);
                 if (mCheckSuccess) {
@@ -90,15 +72,12 @@
                 try {
                     base.evaluate();
                 } finally {
-                    if (mRevertCommand != null || revertSetPropCmd != null) {
-                        String revertCmd =
-                                mRevertCommand != null ? mRevertCommand : revertSetPropCmd;
+                    if (mRevertCommand != null) {
                         final String revertResult = UiDevice.getInstance(
-                                getInstrumentation()).executeShellCommand(
-                                revertCmd);
+                                getInstrumentation()).executeShellCommand(mRevertCommand);
                         if (mCheckSuccess) {
                             Assert.assertTrue(
-                                    "Failed command: " + revertCmd
+                                    "Failed command: " + mRevertCommand
                                             + ", result: " + revertResult,
                                     "Success".equals(result.replaceAll("\\s", "")));
                         }
@@ -141,14 +120,4 @@
         return new ShellCommandRule("settings put global heads_up_notifications_enabled 0",
                 "settings put global heads_up_notifications_enabled 1");
     }
-
-    /**
-     * Enables "InputTransportPublisher" debug flag. This prints the key input events dispatched by
-     * the system server.
-     * adb shell setprop log.tag.InputTransportPublisher DEBUG
-     * See {@link com.android.cts.input.DebugInputRule} for more details.
-     */
-    public static ShellCommandRule createEnableInputTransportPublisherRule() {
-        return new ShellCommandRule("setprop log.tag.InputTransportPublisher DEBUG", null);
-    }
 }
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 8fc4481..d4e061a 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -31,6 +31,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.UserHandle;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.widget.FrameLayout;
 import android.widget.TextView;
@@ -79,7 +80,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mContext = new ActivityContextWrapper(getApplicationContext());
+        mContext = new ActivityContextWrapper(new ContextThemeWrapper(getApplicationContext(),
+                R.style.WidgetContainerTheme));
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
diff --git a/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt b/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt
new file mode 100644
index 0000000..dc6d716
--- /dev/null
+++ b/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt
@@ -0,0 +1,107 @@
+/*
+ * 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 androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry
+import java.lang.reflect.Method
+import java.util.concurrent.atomic.AtomicReference
+import org.junit.runners.model.FrameworkMethod
+import org.junit.runners.model.Statement
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.internal.bytecode.Sandbox
+import org.robolectric.util.ReflectionHelpers
+import org.robolectric.util.ReflectionHelpers.ClassParameter
+
+/** Runner which emulates the provided display before running the actual test */
+class RobolectricDeviceRunner(testClass: Class<*>?, private val deviceName: String?) :
+    RobolectricTestRunner(testClass) {
+
+    private val nameSuffix = deviceName?.let { "-$it" } ?: ""
+
+    override fun getName() = super.getName() + nameSuffix
+
+    override fun testName(method: FrameworkMethod) = super.testName(method) + nameSuffix
+
+    @Throws(Throwable::class)
+    override fun beforeTest(sandbox: Sandbox, method: FrameworkMethod, bootstrappedMethod: Method) {
+        super.beforeTest(sandbox, method, bootstrappedMethod)
+
+        deviceName ?: return
+
+        val emulator =
+            try {
+                ReflectionHelpers.loadClass(
+                    bootstrappedMethod.declaringClass.classLoader,
+                    DEVICE_EMULATOR
+                )
+            } catch (e: Exception) {
+                // Ignore, if the device emulator is not present
+                return
+            }
+        ReflectionHelpers.callStaticMethod<Any>(
+            emulator,
+            "updateDevice",
+            ClassParameter.from(String::class.java, deviceName)
+        )
+    }
+
+    override fun getHelperTestRunner(clazz: Class<*>) = MyHelperTestRunner(clazz)
+
+    class MyHelperTestRunner(clazz: Class<*>) : HelperTestRunner(clazz) {
+
+        override fun methodBlock(method: FrameworkMethod): Statement =
+            // this needs to be run in the test classLoader
+            ReflectionHelpers.callStaticMethod(
+                method.declaringClass.classLoader,
+                RobolectricDeviceRunner::class.qualifiedName,
+                "wrapUiThreadMethod",
+                ClassParameter.from(FrameworkMethod::class.java, method),
+                ClassParameter.from(Statement::class.java, super.methodBlock(method))
+            )
+    }
+
+    private class UiThreadStatement(val base: Statement) : Statement() {
+
+        override fun evaluate() {
+            val exceptionRef = AtomicReference<Throwable>()
+            InstrumentationRegistry.getInstrumentation().runOnMainSync {
+                try {
+                    base.evaluate()
+                } catch (throwable: Throwable) {
+                    exceptionRef.set(throwable)
+                }
+            }
+            exceptionRef.get()?.let { throw it }
+        }
+    }
+
+    companion object {
+
+        private const val DEVICE_EMULATOR = "com.android.launcher3.util.RoboDeviceEmulator"
+
+        @JvmStatic
+        fun wrapUiThreadMethod(method: FrameworkMethod, base: Statement): Statement =
+            if (
+                method.method.isAnnotationPresent(UiThreadTest::class.java) ||
+                    method.declaringClass.isAnnotationPresent(UiThreadTest::class.java)
+            ) {
+                UiThreadStatement(base)
+            } else {
+                base
+            }
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 245ec09..71cd19d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -58,6 +58,7 @@
     private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
     private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
             "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
+    private static final String UNLOCK_BUTTON_VIEW_RES_ID = "ps_lock_unlock_button";
 
     private final int mHeight;
     private final int mIconHeight;
@@ -291,6 +292,10 @@
         return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view");
     }
 
+    protected UiObject2 getAllAppsHeader(UiObject2 allAppsContainer) {
+        return mLauncher.waitForObjectInContainer(allAppsContainer, "all_apps_header");
+    }
+
     protected UiObject2 getSearchBox(UiObject2 allAppsContainer) {
         return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
     }
@@ -416,12 +421,41 @@
         }
     }
 
+    /** Returns PredictionRow if present in view. */
+    @NonNull
+    public PredictionRow getPredictionRowView() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        final UiObject2 allAppsHeader = getAllAppsHeader(allAppsContainer);
+        return new PredictionRow(mLauncher, allAppsHeader);
+    }
+
     /** Returns PrivateSpaceContainer if present in view. */
     @NonNull
     public PrivateSpaceContainer getPrivateSpaceUnlockedView() {
         final UiObject2 allAppsContainer = verifyActiveContainer();
         final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
-        return new PrivateSpaceContainer(mLauncher, appListRecycler);
+        return new PrivateSpaceContainer(mLauncher, appListRecycler, this, true);
+    }
+
+    /** Returns PrivateSpaceContainer in locked state, if present in view. */
+    @NonNull
+    public PrivateSpaceContainer getPrivateSpaceLockedView() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+        return new PrivateSpaceContainer(mLauncher, appListRecycler, this, false);
+    }
+
+    /**
+     * Toggles Lock/Unlock of Private Space, changing the All Apps Ui.
+     */
+    public void togglePrivateSpace() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+        UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(appListRecycler,
+                UNLOCK_BUTTON_VIEW_RES_ID);
+        mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+        mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+        unLockButtonView.click();
     }
 
     protected abstract void verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 68829e0..2e3944d 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -359,6 +359,21 @@
     }
 
     /**
+     * Gets Overview Actions specific to grouped tasks.
+     *
+     * @return The Overview group actions bar
+     */
+    @NonNull
+    public OverviewActions getOverviewGroupActions() {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get overview group actions")) {
+            verifyActiveContainer();
+            UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
+            return new OverviewActions(groupActions, mLauncher);
+        }
+    }
+
+    /**
      * Returns if clear all button is visible.
      */
     public boolean isClearAllVisible() {
@@ -449,10 +464,18 @@
     private void verifyActionsViewVisibility() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to assert overview actions view visibility")) {
+            boolean isTablet = mLauncher.isTablet();
+            OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
+
             if (isActionsViewVisible()) {
-                mLauncher.waitForOverviewObject("action_buttons");
+                if (task.isTaskSplit()) {
+                    mLauncher.waitForOverviewObject("group_action_buttons");
+                } else {
+                    mLauncher.waitForOverviewObject("action_buttons");
+                }
             } else {
                 mLauncher.waitUntilOverviewObjectGone("action_buttons");
+                mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
             }
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 3f96999..200f2ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -24,13 +24,11 @@
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
 import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
 
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
-import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -141,8 +139,6 @@
 
             return new Taskbar(mLauncher);
         } finally {
-            Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                    "swipeUpToUnstashTaskbar: completed gesture");
             mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0a52955..68b0a36 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -31,10 +31,8 @@
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
 import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
 import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 
 import android.app.ActivityManager;
 import android.app.Instrumentation;
@@ -110,7 +108,7 @@
 public final class LauncherInstrumentation {
 
     private static final String TAG = "Tapl";
-    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
+    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 5;
     private static final int GESTURE_STEP_MS = 16;
 
     static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
@@ -206,6 +204,7 @@
     private Runnable mTestAnomalyChecker;
 
     private boolean mCheckEventsForSuccessfulGestures = false;
+    private Runnable mOnFailure;
     private Runnable mOnLauncherCrashed;
 
     private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
@@ -344,6 +343,11 @@
         mCheckEventsForSuccessfulGestures = true;
     }
 
+    /** Sets a runnable that will be invoked upon assertion failures. */
+    public void setOnFailure(Runnable onFailure) {
+        mOnFailure = onFailure;
+    }
+
     public void setOnLauncherCrashed(Runnable onLauncherCrashed) {
         mOnLauncherCrashed = onLauncherCrashed;
     }
@@ -625,6 +629,7 @@
         final String systemAnomalyMessage =
                 getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
         if (systemAnomalyMessage != null) {
+            if (mOnFailure != null) mOnFailure.run();
             Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
                     "http://go/tapl : Tests are broken by a non-Launcher system error: "
                             + systemAnomalyMessage, false)));
@@ -744,6 +749,7 @@
 
     void fail(String message) {
         checkForAnomaly();
+        if (mOnFailure != null) mOnFailure.run();
         Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
                 "http://go/tapl test failure: " + message + ";\nContext: " + getContextDescription()
                         + "; now visible state is " + getVisibleStateMessage(), true)));
@@ -768,7 +774,7 @@
         fail(message + ". " + "Actual: " + actual);
     }
 
-    private void assertEquals(String message, int expected, int actual) {
+    void assertEquals(String message, int expected, int actual) {
         if (expected != actual) {
             fail(message + " expected: " + expected + " but was: " + actual);
         }
@@ -2400,13 +2406,9 @@
             }
 
             if (mEventChecker != null) {
-                testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "eventsCheck: mEventChecker exists");
                 mEventChecker = null;
                 if (mCheckEventsForSuccessfulGestures) {
                     final String message = eventChecker.verify(WAIT_TIME_MS, true);
-                    testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
-                            "mCheckEventsForSuccessfulGestures = true | eventsCheck: message="
-                                    + message);
                     if (message != null) {
                         dumpDiagnostics(message);
                         checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 70d63bd..672c6e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -18,8 +18,6 @@
 import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
 import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
 import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 
 import android.os.SystemClock;
 
@@ -90,7 +88,6 @@
     }
 
     String verify(long waitForExpectedCountMs, boolean successfulGesture) {
-        testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "LogEventChecker.java - verify");
         final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
         if (actualEvents == null) return "null event sequences because launcher likely died";
 
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 99da5c3..6f420af 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -19,10 +19,8 @@
 import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
 import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
 
 import android.graphics.Rect;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -222,7 +220,6 @@
                     return new LaunchedAppState(mLauncher);
                 }
             } else {
-                Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
                 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
                 return new LaunchedAppState(mLauncher);
             }
diff --git a/tests/tapl/com/android/launcher3/tapl/PredictionRow.java b/tests/tapl/com/android/launcher3/tapl/PredictionRow.java
new file mode 100644
index 0000000..11f71fd
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/PredictionRow.java
@@ -0,0 +1,72 @@
+/*
+ * 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.tapl;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+/** View containing prediction app icons */
+public class PredictionRow {
+
+    private static final String PREDICTION_ROW_ID = "prediction_row";
+    private static final String PREDICTION_APP_ID = "icon";
+    private final LauncherInstrumentation mLauncher;
+    private final UiObject2 mAllAppsHeader;
+    private final UiObject2 mPredictionRow;
+
+    PredictionRow(LauncherInstrumentation launcherInstrumentation,
+            UiObject2 allAppsHeader) {
+        mLauncher = launcherInstrumentation;
+        mAllAppsHeader = allAppsHeader;
+        mPredictionRow = mLauncher.waitForObjectInContainer(mAllAppsHeader,
+                PREDICTION_ROW_ID);
+        verifyAppsPresentInsidePredictionRow();
+        verifyPredictionRowAppsCount();
+    }
+
+    /** Verify that one app is present in prediction row view. */
+    private void verifyAppsPresentInsidePredictionRow() {
+        mLauncher.waitForObjectInContainer(mPredictionRow,
+                PREDICTION_APP_ID);
+    }
+
+    /** Verify that prediction row apps count is same as launcher apps column count. */
+    private void verifyPredictionRowAppsCount() {
+        mLauncher.assertEquals("PredictionRow app count mismatch", mLauncher.getNumAllAppsColumns(),
+                getPredictionRowAppsCount());
+    }
+
+    /**
+     * Returns an app icon found in the prediction row. This fails if any icon is not
+     * found.
+     */
+    @NonNull
+    private HomeAppIcon getAnyAppIcon() {
+        return new AllAppsAppIcon(mLauncher,
+                mPredictionRow.findObject(AppIcon.getAnyAppIconSelector()));
+    }
+
+    /**
+     * Returns the size of prediction row apps count.
+     */
+    private int getPredictionRowAppsCount() {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get all prediction row icons")) {
+            return mPredictionRow.findObjects(AppIcon.getAnyAppIconSelector()).size();
+        }
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
index 2c16e01..a2814f0 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.tapl;
 
+import android.graphics.Point;
+
 import androidx.test.uiautomator.UiObject2;
 
 /**
@@ -23,20 +25,30 @@
  */
 public class PrivateSpaceContainer {
     private static final String PS_HEADER_RES_ID = "ps_header_layout";
-    private static final String INSTALL_APP_TITLE = "Install apps";
+    private static final String INSTALL_APP_TITLE = "Install";
     private static final String DIVIDER_RES_ID = "private_space_divider";
 
     private final LauncherInstrumentation mLauncher;
     private final UiObject2 mAppListRecycler;
+    private final AllApps mAppList;
+    private final boolean mPrivateSpaceEnabled;
 
     PrivateSpaceContainer(LauncherInstrumentation launcherInstrumentation,
-            UiObject2 appListRecycler) {
+            UiObject2 appListRecycler, AllApps appList, boolean privateSpaceEnabled) {
         mLauncher = launcherInstrumentation;
         mAppListRecycler = appListRecycler;
+        mAppList = appList;
+        mPrivateSpaceEnabled = privateSpaceEnabled;
 
-        verifyHeaderIsPresent();
-        verifyInstallAppButtonIsPresent();
-        verifyDividerIsPresent();
+        if (mPrivateSpaceEnabled) {
+            verifyHeaderIsPresent();
+            verifyInstallAppButtonIsPresent();
+            verifyDividerIsPresent();
+        } else {
+            verifyHeaderIsPresent();
+            verifyInstallAppButtonIsNotPresent();
+            verifyDividerIsNotPresent();
+        }
     }
 
     // Assert PS Header is in view.
@@ -44,17 +56,39 @@
     private void verifyHeaderIsPresent() {
         final UiObject2 psHeader = mLauncher.waitForObjectInContainer(mAppListRecycler,
                 PS_HEADER_RES_ID);
-        new PrivateSpaceHeader(mLauncher, psHeader, true);
+        new PrivateSpaceHeader(mLauncher, psHeader, mPrivateSpaceEnabled);
     }
 
 
     // Assert Install App Item is present in view.
     private void verifyInstallAppButtonIsPresent() {
-        mLauncher.getAllApps().getAppIcon(INSTALL_APP_TITLE);
+        mAppList.getAppIcon(INSTALL_APP_TITLE);
+    }
+
+    // Assert Install App Item is not present in view.
+    private void verifyInstallAppButtonIsNotPresent() {
+        mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
     }
 
     // Assert Sys App Divider is present in view.
     private void verifyDividerIsPresent() {
         mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
     }
-}
+
+    // Assert Sys App Divider is not present in view.
+    private void verifyDividerIsNotPresent() {
+        mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
+    }
+
+    /**
+     * Verifies that a user installed app is present above the divider.
+     */
+    public void verifyInstalledAppIsPresent(String appName) {
+        AppIcon appIcon = mAppList.getAppIcon(appName);
+        final Point iconCenter = appIcon.mObject.getVisibleCenter();
+        UiObject2 divider = mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
+        final Point dividerCenter = divider.getVisibleCenter();
+        mLauncher.assertTrue("Installed App: " + appName + " is not above the divider",
+                iconCenter.y < dividerCenter.y);
+    }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
index 3a7f038..cc64aae 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
@@ -45,7 +45,7 @@
         if (mPrivateSpaceEnabled) {
             verifyUnlockedState();
         } else {
-            mLauncher.fail("Private Space found in non enabled state");
+            verifyLockedState();
         }
     }
 
@@ -74,4 +74,23 @@
         mLauncher.assertEquals("PS lock text is incorrect", "Lock", lockText.getText());
 
     }
+
+    /** Verify Locked State elements in Private Space Header */
+    private void verifyLockedState() {
+        UiObject2 headerText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                PS_HEADER_TEXT_RES_ID);
+        mLauncher.assertEquals("PS Header Text is incorrect ",
+                "Private", headerText.getText());
+
+        UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                UNLOCK_BUTTON_VIEW_RES_ID);
+        mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+        mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+
+        mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                LOCK_ICON_RES_ID);
+
+        mLauncher.waitUntilLauncherObjectGone(SETTINGS_BUTTON_RES_ID);
+        mLauncher.waitUntilLauncherObjectGone(LOCK_TEXT_RES_ID);
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 8d3a631..4be46ab 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 
+import android.text.TextUtils;
 import android.widget.TextView;
 
 import androidx.test.uiautomator.By;
@@ -117,4 +118,28 @@
     public SearchResultFromQsb getSearchResultForInput() {
         return this;
     }
+
+    /** Verify a tile is present by checking its title and subtitle. */
+    public void verifyTileIsPresent(String title, String subtitle) {
+        ArrayList<UiObject2> searchResults =
+                new ArrayList<>(mLauncher.waitForObjectsInContainer(
+                        mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
+                        By.clazz(TextView.class)));
+        boolean foundTitle = false;
+        boolean foundSubtitle = false;
+        for (UiObject2 uiObject: searchResults) {
+            String currentString = uiObject.getText();
+            if (TextUtils.equals(currentString, title)) {
+                foundTitle = true;
+            } else if (TextUtils.equals(currentString, subtitle)) {
+                foundSubtitle = true;
+            }
+        }
+        if (!foundTitle) {
+            mLauncher.fail("Tile not found for title: " + title);
+        }
+        if (!foundSubtitle) {
+            mLauncher.fail("Tile not found for subtitle: " + subtitle);
+        }
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index d176136..4fa93ef 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -347,6 +347,7 @@
      */
     public Map<String, Point> getWorkspaceIconsPositions() {
         final UiObject2 workspace = verifyActiveContainer();
+        mLauncher.waitForLauncherInitialized(); // b/319501259
         List<UiObject2> workspaceIcons =
                 mLauncher.waitForObjectsInContainer(workspace, AppIcon.getAnyAppIconSelector());
         return workspaceIcons.stream()