Merge "Add logging for each migration type" into main
diff --git a/Android.bp b/Android.bp
index 85632b2..2c4fb37 100644
--- a/Android.bp
+++ b/Android.bp
@@ -409,6 +409,9 @@
     lint: {
         baseline_filename: "lint-baseline.xml",
     },
+    flags_packages: [
+        "com_android_launcher3_flags",
+    ],
 }
 
 //
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6948133..768ba65 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,10 @@
 [Builtin Hooks]
 ktfmt = true
+bpfmt = true
 
 [Builtin Hooks Options]
 ktfmt = --kotlinlang-style
+bpfmt = -d
 
 [Tool Paths]
 ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index c5774bb..cd8b891 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -311,6 +311,13 @@
 }
 
 flag {
+    name: "all_apps_blur"
+    namespace: "launcher"
+    description: "Content behind the all apps panel in Launcher will be blurred."
+    bug: "400827727"
+}
+
+flag {
     name: "multiline_search_bar"
     namespace: "launcher"
     description: "Search bar can wrap to multi-line"
@@ -559,6 +566,14 @@
 }
 
 flag {
+  name: "google_sans_flex_font"
+  namespace: "launcher"
+  description: "Adds refresh for font family. Needs to be fixed to be used in resources."
+  bug: "395145453"
+  is_fixed_read_only: true
+}
+
+flag {
   name: "restore_archived_shortcuts"
   namespace: "launcher"
   description: "Makes sure pre-archived pinned shortcuts also get restored"
@@ -656,3 +671,23 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "sync_app_launch_with_taskbar_stash"
+  namespace: "launcher"
+  description: "Syncs the two animations (app launch, taskbar stash) so they play at the same time."
+  bug: "319162553"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+  name: "remove_apps_refresh_on_right_click"
+  namespace: "launcher"
+  description: "Remove predicted apps refresh on right click"
+  bug: "343650193"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/quickstep/res/color/app_chip_menu_item_color_fg.xml b/quickstep/res/color/app_chip_menu_item_color_fg.xml
new file mode 100644
index 0000000..fa1dc34
--- /dev/null
+++ b/quickstep/res/color/app_chip_menu_item_color_fg.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.15" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_pressed="true" />
+    <item android:alpha="0.11" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_hovered="true" />
+    <item android:color="@android:color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/quickstep/res/color/app_chip_state_color_fg.xml b/quickstep/res/color/app_chip_state_color_fg.xml
new file mode 100644
index 0000000..58dfee0
--- /dev/null
+++ b/quickstep/res/color/app_chip_state_color_fg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.15" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_pressed="true" />
+    <item android:alpha="0.11" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_hovered="true" />
+    <item android:color="@android:color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/app_chip_fg.xml b/quickstep/res/drawable/app_chip_fg.xml
new file mode 100644
index 0000000..7b19c9e
--- /dev/null
+++ b/quickstep/res/drawable/app_chip_fg.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/app_chip_state_color_fg" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/app_chip_menu_item_bg.xml b/quickstep/res/drawable/app_chip_menu_item_bg.xml
new file mode 100644
index 0000000..39e88d2
--- /dev/null
+++ b/quickstep/res/drawable/app_chip_menu_item_bg.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/materialColorSurfaceBright" />
+</shape>
diff --git a/quickstep/res/drawable/app_chip_menu_item_fg.xml b/quickstep/res/drawable/app_chip_menu_item_fg.xml
new file mode 100644
index 0000000..96d067d
--- /dev/null
+++ b/quickstep/res/drawable/app_chip_menu_item_fg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/app_chip_menu_item_color_fg" />
+    <corners android:radius="@dimen/task_menu_item_corner_radius" />
+</shape>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index b44510d..b45a04a 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -21,14 +21,14 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
-    android:background="@drawable/keyboard_quick_switch_task_view_background"
-    android:clipToOutline="true"
-    launcher:focusBorderColor="@color/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorSecondary">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
         android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_task_view_background"
+        android:clipToOutline="true"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
index 56b1adf..672b715 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
@@ -21,14 +21,14 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
-    android:background="@drawable/keyboard_quick_switch_task_view_background"
-    android:clipToOutline="true"
-    launcher:focusBorderColor="@androidprv:color/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorSecondary">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
         android:layout_width="0dp"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_task_view_background"
+        android:clipToOutline="true"
 
         app:layout_constraintDimensionRatio="1:1"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
index 0972be1..09fb509 100644
--- a/quickstep/res/layout/icon_app_chip_view.xml
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -22,10 +22,12 @@
     android:layout_width="@dimen/task_thumbnail_icon_menu_expanded_width"
     android:layout_height="@dimen/task_thumbnail_icon_menu_expanded_height"
     android:clipToOutline="true"
-    android:focusable="false"
+    android:focusable="true"
+    android:focusableInTouchMode="false"
     android:importantForAccessibility="no"
     android:autoMirrored="true"
     android:elevation="@dimen/task_thumbnail_icon_menu_elevation"
+    android:foreground="@drawable/app_chip_fg"
     android:background="@color/materialColorSurfaceBright">
 
     <!-- ignoring warning because the user of the anchor is a Rect where RTL is not needed -->
@@ -77,4 +79,5 @@
         android:background="@drawable/icon_menu_arrow_background"
         android:src="@drawable/ic_chevron_down"
         android:importantForAccessibility="no" />
+
 </com.android.quickstep.views.IconAppChipView>
\ No newline at end of file
diff --git a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
index db47ff0..d281732 100644
--- a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
@@ -20,9 +20,8 @@
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="@androidprv:color/materialColorOutline"
+    launcher:focusBorderColor="@color/materialColorSecondary"
     launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -31,6 +30,7 @@
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
         android:background="@drawable/keyboard_quick_switch_text_button_background"
         android:backgroundTint="@androidprv:color/materialColorSurfaceContainer"
+        android:clipToOutline="true"
         android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
index 5a3ee83..3321306 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
@@ -20,9 +20,8 @@
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="@androidprv:color/materialColorOutline"
+    launcher:focusBorderColor="@color/materialColorSecondary"
     launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -31,6 +30,7 @@
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
         android:background="@drawable/keyboard_quick_switch_text_button_background"
         android:backgroundTint="@androidprv:color/materialColorSurfaceBright"
+        android:clipToOutline="true"
         android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 37bb027..218a3f2 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -21,14 +21,14 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
-    android:background="@drawable/keyboard_quick_switch_task_view_background"
-    android:clipToOutline="true"
-    launcher:focusBorderColor="@color/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorSecondary">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
         android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_task_view_background"
+        android:clipToOutline="true"
 
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
index 33d8c16..d3f5bf1 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
@@ -21,14 +21,14 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:importantForAccessibility="yes"
-    android:background="@drawable/keyboard_quick_switch_task_view_background"
-    android:clipToOutline="true"
-    launcher:focusBorderColor="@androidprv:color/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorSecondary">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
         android:layout_width="0dp"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+        android:background="@drawable/keyboard_quick_switch_task_view_background"
+        android:clipToOutline="true"
 
         app:layout_constraintDimensionRatio="1:1"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/quickstep/res/layout/task_header_view.xml b/quickstep/res/layout/task_header_view.xml
index ea5c24e..849153f 100644
--- a/quickstep/res/layout/task_header_view.xml
+++ b/quickstep/res/layout/task_header_view.xml
@@ -15,52 +15,48 @@
 -->
 <com.android.quickstep.views.TaskHeaderView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/task_header_view"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:id="@+id/task_header_view"
+    android:paddingTop="@dimen/task_thumbnail_header_padding_top_bottom"
+    android:paddingBottom="@dimen/task_thumbnail_header_padding_top_bottom"
+    android:paddingStart="@dimen/task_thumbnail_header_padding_start_end"
+    android:paddingEnd="@dimen/task_thumbnail_header_padding_start_end"
     android:background="@drawable/task_thumbnail_header_bg">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/task_thumbnail_header_height"
-        android:layout_marginStart="@dimen/task_thumbnail_header_margin_edge"
-        android:layout_marginEnd="@dimen/task_thumbnail_header_margin_edge"
+    <ImageView
+        android:id="@+id/header_app_icon"
+        android:layout_width="@dimen/task_thumbnail_header_icon_size"
+        android:layout_height="@dimen/task_thumbnail_header_icon_size"
+        android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
+        android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
+        android:contentDescription="@string/header_app_icon_description"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+    <TextView
+        android:id="@+id/header_app_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
+        android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
+        android:maxLines="1"
+        android:text="@string/header_default_app_title"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@id/header_app_icon"
+        app:layout_constraintTop_toTopOf="parent" />
+    <ImageButton
+        android:id="@+id/header_close_button"
+        android:layout_width="@dimen/task_thumbnail_header_icon_size"
+        android:layout_height="@dimen/task_thumbnail_header_icon_size"
+        android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
+        android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
+        android:background="@null"
+        android:contentDescription="@string/header_close_icon_description"
+        android:src="@drawable/task_header_close_button"
+        android:tint="@android:color/darker_gray"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent">
-        <ImageView
-            android:id="@+id/header_app_icon"
-            android:contentDescription="@string/header_app_icon_description"
-            android:layout_width="@dimen/task_thumbnail_header_icon_size"
-            android:layout_height="@dimen/task_thumbnail_header_icon_size"
-            android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toStartOf="@id/header_app_title"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent" />
-        <TextView
-            android:id="@+id/header_app_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
-            android:maxLines="1"
-            android:text="@string/header_default_app_title"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toEndOf="@id/header_app_icon"
-            app:layout_constraintTop_toTopOf="parent" />
-        <ImageButton
-            android:id="@+id/header_close_button"
-            android:contentDescription="@string/header_close_icon_description"
-            android:layout_width="@dimen/task_thumbnail_header_icon_size"
-            android:layout_height="@dimen/task_thumbnail_header_icon_size"
-            android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
-            android:src="@drawable/task_header_close_button"
-            android:tint="@android:color/darker_gray"
-            android:background="@null"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toEndOf="@id/header_app_title"
-            app:layout_constraintHorizontal_bias="1" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
+        app:layout_constraintHorizontal_bias="1"
+        app:layout_constraintStart_toEndOf="@id/header_app_title"
+        app:layout_constraintTop_toTopOf="parent" />
 </com.android.quickstep.views.TaskHeaderView>
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 7a6435b..83e6f79 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taakbalkoorloop"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Maak app as ’n borrel oop"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Werkskerm"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Appikoon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Maak Toe-knoppie"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Speld aan taakbalk vas"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ontspeld van taakbalk"</string>
 </resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 7286f3f..d596734 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"የተግባር አሞሌ ትርፍ ፍሰት"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"መተግበሪያን እንደ ዓረፋ ይክፈቱ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ዴስክቶፕ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"የመተግበሪያ አዶ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"የመተግበሪያ ርዕስ"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"የዝጋ አዝራር"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ተግባር አሞሌ ላይ ፒን አድርግ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ከተግባር አሞሌ ንቀል"</string>
 </resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index e673ac6..ec37983 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"القائمة الكاملة لشريط التطبيقات"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"فتح التطبيق كفقاعة"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"وضع الكمبيوتر المكتبي"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"‫\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" من \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"رمز التطبيق"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"عنوان التطبيق"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"زر الإغلاق"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"التثبيت على شريط التطبيقات"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"إزالة التثبيت من شريط التطبيقات"</string>
 </resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 4f3c22d..9cadc10 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"টাস্কবাৰ অ’ভাৰফ্ল"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"বাবল হিচাপে এপ্‌টো খোলক"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্‌}one{অধিক এপ্‌}other{অধিক এপ্‌}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"এপৰ আইকন"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"এপৰ শিৰোনাম"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"বন্ধ কৰা বুটাম"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"টাস্কবাৰত পিন কৰক"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"টাস্কবাৰৰ পৰা আনপিন কৰক"</string>
 </resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index f7f22e2..bf34d27 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tapşırıqlar Paneli üzrə əlavə menyu"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Tətbiqi yumrucuq kimi açın"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Tətbiq ikonası"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Tətbiq başlığı"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Qapatma düyməsi"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"İşləmə panelinə bərkidin"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"İşləmə panelindən çıxarın"</string>
 </resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 67ecbcd..14724e9 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Preklopna traka zadataka"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Naziv aplikacije"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Dugme Zatvori"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Zakači za traku zad."</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkači sa trake zad."</string>
 </resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 436ed3f..5f55b41 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Меню з пашырэннем панэлі задач"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Адкрыць праграму ва ўсплывальным акне"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Працоўны стол"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, крыніца: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Значок праграмы"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Назва праграмы"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрыць\""</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Замацаваць на панэлі"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Адмацаваць ад панэлі"</string>
 </resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 922a473..871501f 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Меню при препълване на лентата на задачите"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отваряне на приложението като балонче"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за настолни компютри"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Икона на приложението"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Име на приложението"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Бутон за затваряне"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Лент. на зад.: фикс."</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Лент. на зад.: осв."</string>
 </resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 974994a..a1e30bb 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"টাস্কবার ওভারফ্লো"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"বাবল হিসেবে অ্যাপ খুলুন"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"অ্যাপ আইকন"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"অ্যাপের শিরোনাম"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"বন্ধ করার বোতাম"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"টাস্কবারে পিন করুন"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"টাস্কবার থেকে আনপিন করুন"</string>
 </resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index c89f84a..57aa3c3 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Preklopni meni trake zadataka"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Naslov aplikacije"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Dugme za zatvaranje"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Zakači na traku zadataka"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkači s trake zadataka"</string>
 </resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 87591da..e729ff5 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Menú addicional de la barra de tasques"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Obre l\'aplicació com a bombolla"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Escriptori"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icona de l\'aplicació"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Títol de l\'aplicació"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Botó Tanca"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixa a barra tasques"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Deixa de fixar"</string>
 </resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6d53ca8..5106ae3 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Přetečení panelu aplikací"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otevřít aplikaci jako bublinu"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikace"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Název aplikace"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Tlačítko Zavřít"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Připnout na panel"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odepnout z panelu"</string>
 </resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index debea45..1328da9 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Prikmenu på proceslinjen"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Åbn appen som en boble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Computertilstand"</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>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Knappen Luk"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fastgør til proceslinje"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Frigør fra proceslinje"</string>
 </resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index b4d5ac1..2074d5e 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Dreipunkt-Menü der Taskleiste"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"App als Bubble öffnen"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktopmodus"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ aus <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"App-Symbol"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titel der App"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Schaltfläche „Schließen“"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"An Taskleiste pinnen"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Von Taskleiste lösen"</string>
 </resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 5dde857..8951e20 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Υπερχείλιση γραμμής εργαλείων"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Άνοιγμα εφαρμογής σε συννεφάκι"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Υπολογιστής"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Εικονίδιο εφαρμογής"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Τίτλος εφαρμογής"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Κουμπί κλεισίματος"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Καρφ. σε γρ. εργαλ."</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ξεκαρφ. από γρ. εργαλ."</string>
 </resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index eef812c..18e5984 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string>
 </resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index d1319ce..8f52c66 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index eef812c..18e5984 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string>
 </resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index eef812c..18e5984 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string>
 </resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 17e3a7d..d909af1 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir app como burbuja"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 69628cf..016e579 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -92,7 +92,7 @@
     <string name="allset_button_hint" msgid="2395219947744706291">"Toca el botón de inicio para ir a la pantalla de inicio"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes empezar a usar tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
-    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ajustes de navegación del sistema"</annotation></string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Opciones de navegación"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barra de tareas ampliada"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir aplicación como burbuja"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icono de la aplicación"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Título de la aplicación"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Botón de cerrar"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fijar a la barra"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Desfijar de la barra"</string>
 </resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 41cb357..ecf59af 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tegumiriba ületäide"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Rakenduse avamine mullina"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Lauaarvuti"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Rakenduse ikoon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Rakenduse pealkiri"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Sulgemisnupp"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Tegumiribale kinnitamine"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Tegumiribalt vabastamine"</string>
 </resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 15c4742..90748c0 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Zereginen barraren luzapena"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ireki aplikazioa burbuila gisa"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenagailua"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Aplikazioaren ikonoa"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Aplikazioaren izena"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Ixteko botoia"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Ainguratu zereginen barran"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Kendu aingura zereginen barratik"</string>
 </resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 810632b..ee9ed1d 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"سرریز نوار وظیفه"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"باز کردن برنامه به‌صورت حبابک"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"رایانه"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"نماد برنامه"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"عنوان برنامه"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"دکمه بستن"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"سنجاق به نوار وظیفه"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"برداشتن از نواروظیفه"</string>
 </resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index e23ae30..f681e0d 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tehtäväpalkin ylivuotu"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Avaa sovellus kuplana"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Tietokone"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Sovelluskuvake"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Sovelluksen nimi"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Sulje-painike"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Kiinnitä palkkiin"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Poista palkista"</string>
 </resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 448abf5..5b1f149 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barre des tâches à développer"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ouvrir l\'appli sous forme de bulle"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"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>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icône de l\'appli"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Nom de l\'appli"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Bouton Fermer"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Éping. (barre tâche)"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Détacher (bar. tâc.)"</string>
 </resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 59310e2..95b448d 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Développement de la barre des tâches"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ouvrir l\'appli sous forme de bulle"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Mode ordinateur"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icône de l\'application"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titre de l\'application"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Bouton \"Fermer\""</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Épingler à la barre"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Désépingler de la barre"</string>
 </resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 994b5fd..e59b451 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Menú adicional da barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir aplicación como unha burbulla"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icona da aplicación"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Título da aplicación"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Botón Pechar"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixar na barra"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Soltar da barra"</string>
 </resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 03fbd63..b0238d0 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ટાસ્કબાર ઓવરફ્લો"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"બબલ તરીકે ઍપ ખોલો"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ડેસ્કટૉપ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>થી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ઍપનું આઇકન"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ઍપનું શીર્ષક"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\'બંધ કરો\' બટન"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ટાસ્કબારમાં પિન કરો"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ટાસ્કબારમાંથી અનપિન કરો"</string>
 </resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 89648d4..6aba44c 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओवरफ़्लो आइकॉन"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ऐप्लिकेशन को बबल के तौर पर खोलें"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> की <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> वाली सूचना"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ऐप्लिकेशन आइकॉन"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ऐप्लिकेशन का नाम"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\'बंद करें\' बटन"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबार में पिन करें"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबार से अनपिन करें"</string>
 </resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index e4a0f7c..963ce57 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Dodatni izbornik trake sa zadacima"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Računalo"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Naziv aplikacije"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Gumb Zatvori"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Prikvači na traku"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkvači s trake"</string>
 </resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index ac97372..093c92d 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Feladatsáv túlcsordulása"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Alkalmazás megnyitása buborékként"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Asztali"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, forrás: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Alkalmazásikon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Alkalmazás neve"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Bezárás gomb"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Kitűzés a feladatsávon"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Kitűzés feloldása"</string>
 </resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 27ac837..0fa5d2d 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Հավելվածների վահանակի լրացուցիչ ընտրացանկ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Բացել հավելվածը պղպջակի ձևով"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Համակարգիչ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածից"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Հավելվածի պատկերակ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Հավելվածի անվանում"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"«Փակել» կոճակ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Ամրացնել վահանակում"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ապամրացնել վահանակից"</string>
 </resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 69a2a82..fe28340 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tambahan Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Buka aplikasi sebagai balon"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikon aplikasi"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Judul aplikasi"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Tombol tutup"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Sematkan ke taskbar"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Lepaskan dari taskbar"</string>
 </resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index a8c2770..a0657dd 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Yfirflæði á forritastiku"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Opna forrit sem blöðru"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{forrit til viðbótar}one{forrit til viðbótar}other{forrit til viðbótar}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Skjáborð"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Forritstákn"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titil forrits"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Hnappur til að loka"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Festa á forritastiku"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Losa af forritastiku"</string>
 </resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 7d0bcd8..bc795e4 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Overflow barra delle app"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Apri l\'app come fumetto"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icona dell\'app"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titolo dell\'app"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Pulsante Chiudi"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fissa alla barra app"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Sblocca da barra app"</string>
 </resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 55295cf..3f5ddfc 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"אפשרויות נוספות בסרגל האפליקציות"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"פתיחת האפליקציה בבועה"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"מחשב"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"‫<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מתוך <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"סמל האפליקציה"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"שם האפליקציה"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"כפתור הסגירה"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"הצמדה לסרגל האפליקציות"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ביטול ההצמדה לסרגל"</string>
 </resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index b66126f..d6f64a5 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -140,9 +140,15 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string>
     <string name="open_app_as_a_bubble" msgid="6642626287247807473">"アプリをバブルとして開く"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"デスクトップ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 0608631..1ea1eea 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -140,9 +140,15 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string>
     <string name="open_app_as_a_bubble" msgid="6642626287247807473">"აპის გახსნა ბუშტის სახით"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"დესკტოპი"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>-იდან"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 8e18fab..b06ac37 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"\"Тапсырмалар жолағы\" қосымша мәзірі"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Қолданбаны қалқыма терезе түрінде ашу"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ұсынатын <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Қолданба белгішесі"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Қолданба атауы"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\"Жабу\" түймесі"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Тапсырмалар жолағына бекіту"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Тапсырмалар жолағынан босату"</string>
 </resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 44f7fe4..6686851 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ម៉ឺនុយបន្ថែមរបារកិច្ចការ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"បើកកម្មវិធីជាផ្ទាំងសារ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"អេក្រង់ដើម"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"រូបកម្មវិធី"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ចំណងជើងកម្មវិធី"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"ប៊ូតុងបិទ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ខ្ទាស់ទៅរបារកិច្ចការ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ដកខ្ទាស់ពីរបារកិច្ចការ"</string>
 </resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 2187634..3bb3d46 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -140,9 +140,15 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ಆ್ಯಪ್ ಅನ್ನು ಬಬಲ್ ಆಗಿ ತೆರೆಯಿರಿ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್‌ಗಳು}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ಡೆಸ್ಕ್‌ಟಾಪ್"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್‌ಫ್ಲೋ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಂದ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index e5e5359..367908f 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"태스크 바 오버플로"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"앱을 대화창으로 열기"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"데스크톱"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"앱 아이콘"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"앱 제목"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"닫기 버튼"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"태스크 바에 고정"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"태스크 바에서 고정 해제"</string>
 </resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index d23ee7e..834e38f 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"\"Тапшырмалар панели\" кошумча менюсу"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Колдонмону көбүкчө катары ачуу"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Колдонмонун сүрөтчөсү"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Колдонмонун аталышы"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Жабуу баскычы"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Тапшырмалар панелине кадоо"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Тапшырмалар панелинен алып коюу"</string>
 </resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 8407311..80b745b 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ສ່ວນເພີ່ມເຕີມຂອງແຖບໜ້າວຽກ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ເປີດແອັບເປັນຟອງ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ເດັສທັອບ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ໄອຄອນແອັບ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ຊື່ແອັບ"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"ປຸ່ມປິດ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ປັກໝຸດໄປໃສ່ແຖບໜ້າວຽກ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ຖອດປັກໝຸດຈາກແຖບໜ້າວຽກ"</string>
 </resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 268eeb7..bb1fff3 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Atidaryti programą kaip burbulą"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildoma programa}one{papildoma programa}few{papildomos programos}many{papildomos programos}other{papildomų programų}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Stalinis kompiuteris"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index ad83c24..c3c21a6 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Uzdevumu joslas pārpilde"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Atvērt lietotni kā burbuli"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Darbvirsma"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Lietotnes ikona"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Lietotnes nosaukums"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Poga Aizvērt"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Piespraust uzdevumu joslai"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Atspraust no uzdevumu joslas"</string>
 </resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 96edee6..7362c82 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Проширено балонче на „Лента со задачи“"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отвори апликација како балонче"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за компјутер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Икона за апликацијата"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Наслов на апликацијата"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Копче за затворање"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Закачи на лентата"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Откачи од лентата"</string>
 </resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 628acd1..9aa1d1c 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ടാസ്‌ക്ബാർ ഓവർഫ്ലോ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ആപ്പ് ഒരു ബബിളായി തുറക്കുക"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ഡെസ്‌ക്ടോപ്പ്"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ആപ്പ് ഐക്കൺ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ആപ്പിന്റെ പേര്"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"അടയ്ക്കുക ബട്ടൺ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ടാസ്ക്ബാറിൽ ചേർക്കൂ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ടാസ്ക്ബാറിൽ നിന്ന് മാറ്റൂ"</string>
 </resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index ac3c40e..129b75c 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Ажлын хэсгийн урт цэс"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Аппыг бөмбөлөг байдлаар нээх"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Дэлгэц"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>-с ирсэн <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Aппын дүрс тэмдэг"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Аппын нэр"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Хаах товч"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Ажлын хэсэгт бэхлэх"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Бэхэлснийг болиулах"</string>
 </resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 6f82343..818b824 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओव्हरफ्लो"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"बबल म्हणून अ‍ॅप उघडा"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अ‍ॅप}other{आणखी अ‍ॅप्स}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> वरील <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"अ‍ॅपचा आयकन"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"अ‍ॅपचे शीर्षक"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"बंद करा बटण"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबारवर पिन करा"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबारवरून अनपिन करा"</string>
 </resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index b85b62c..c06811b 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Limpahan Bar Tugas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Buka apl sebagai gelembung"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikon apl"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Tajuk apl"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Butang tutup"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Semat pada bar tugas"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Nyahsemat drpd bar tugas"</string>
 </resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 467ef26..b556ded 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar မီနူးအပို"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"အက်ပ်ကို ပူဖောင်းကွက်အဖြစ် ဖွင့်ရန်"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ဒက်စ်တော့"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"အက်ပ်သင်္ကေတ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"အက်ပ်ခေါင်းစဉ်"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"အပိတ် ခလုတ်"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Taskbar ၌ ပင်ထိုးရန်"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Taskbar မှ ဖြုတ်ရန်"</string>
 </resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 2690a61..4528a83 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Overflyt for oppgavelinjen"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Åpne appen som en boble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Skrivebord"</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>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Apptittel"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Lukkeknapp"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fest i oppgavelinjen"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Løsne i oppgavelinje"</string>
 </resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index d03fcce..2d35a22 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओभरफ्लो"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"एपलाई बबलका रूपमा खोल्नुहोस्"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटप"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> मा देखाइएका <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"एप जनाउने आइकन"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"एपको शीर्षक"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\"बन्द गर्नुहोस्\" बटन"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबारमा पिन गर्नुहोस्"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबारबाट पिन गर्नुहोस्"</string>
 </resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index d265f96..3086c40 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taakbalkoverloop"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"App openen als ballon"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Icoon van app"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titel van app"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Knop Sluiten"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Vastzetten op taakbalk"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Losmaken van taakbalk"</string>
 </resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index e19fee5..4581f97 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ଟାସ୍କବାର ଓଭରଫ୍ଲୋ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ଏକ ବବଲ ଭାବେ ଆପ ଖୋଲନ୍ତୁ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ଡେସ୍କଟପ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ଆପ ଆଇକନ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ଆପ ଟାଇଟେଲ"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\"ବନ୍ଦ କରନ୍ତୁ\" ବଟନ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ଟାସ୍କବାରରେ ପିନ କର"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ଟାସ୍କବାରରୁ ଅନପିନ କର"</string>
 </resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 4a015e4..ac88e6f 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ਟਾਸਕਬਾਰ ਓਵਰਫ਼ਲੋ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ਐਪ ਨੂੰ ਬਬਲ ਵਜੋਂ ਖੋਲ੍ਹੋ"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ਡੈਸਕਟਾਪ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ਐਪ ਪ੍ਰਤੀਕ"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ਐਪ ਸਿਰਲੇਖ"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\'ਬੰਦ ਕਰੋ\' ਬਟਨ"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ਟਾਸਕਬਾਰ \'ਤੇ ਪਿੰਨ ਕਰੋ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ਟਾਸਕਬਾਰ ਤੋਂ ਅਣਪਿੰਨ ਕਰੋ"</string>
 </resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 89297a2..090dc4c 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Rozwijany pasek aplikacji"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otwórz aplikację jako dymek"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Pulpit"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacji"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Tytuł aplikacji"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Przycisk Zamknij"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Przypnij do paska"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odepnij od paska"</string>
 </resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 8c38182..ff5dbf7 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir app como um balão"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 5ea0194..bc0b838 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barra de tarefas flutuante"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir o app como um balão"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ícone do app"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Título do app"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Botão \"Fechar\""</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixar na barra de tarefas"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Liberar da barra de tarefas"</string>
 </resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 08e4081..0d1aab1 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Meniu suplimentar pentru bara de activități"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Deschide aplicația ca balon"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicație suplimentară}few{mai multe aplicații}other{mai multe aplicații}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Pictograma aplicației"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titlul aplicației"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Buton de închidere"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixează pe bara de activități"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Anulează fixarea din bara de activități"</string>
 </resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 65af36f..3cf299d 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Дополнительное меню панели задач"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Открыть приложение во всплывающем окне"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим компьютера"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Значок приложения"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Название приложения"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрыть\""</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Закрепить на панели"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Открепить от панели"</string>
 </resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 7e00beb..0b4efc4 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"කාර්ය තීරුව පිටාර යාම"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"යෙදුම බුබුලක් ලෙස විවෘත කරන්න"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ඩෙස්ක්ටොපය"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> සිට <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"යෙදුම් නිරූපකය"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"යෙදුම් මාතෘකාව"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"වැසීමේ බොත්තම"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"කාර්ය තීරුවට අමුණන්න"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"කාර්ය තීරුවෙන් ඉවත් කරන්න"</string>
 </resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 1170e71..9ca4ae7 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Rozšírená ponuka panela aplikácií"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvoriť aplikáciu ako bublinu"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ďalšia aplikácia}few{ďalšie aplikácie}many{ďalšie aplikácie}other{ďalšie aplikácie}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikácie"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Názov aplikácie"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Tlačidlo Zavrieť"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Pripnúť na panel"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odopnúť z panela"</string>
 </resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 9ed661c..9a437bc 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Odpri aplikacijo kot oblaček"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}two{dodatni aplikaciji}few{dodatne aplikacije}other{dodatnih aplikacij}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Namizni računalnik"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 965699d..c72b926 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tejkalimi i shiritit të detyrave"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Hap aplikacionin si një flluskë"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona e aplikacionit"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Titulli i aplikacionit"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Butoni i mbylljes"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Gozhdo te shiriti"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Zhgozhdo nga shiriti"</string>
 </resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index c827cda..c418302 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Преклопна трака задатака"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отвори апликацију као облачић"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Рачунар"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Икона апликације"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Назив апликације"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Дугме Затвори"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Закачи за траку зад."</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Откачи са траке зад."</string>
 </resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 5713036..76c8d3d 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Fler alternativ för aktivitetsfältet"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Öppna appen som en bubbla"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Skrivbordsläge"</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>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Knappen Stäng"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Fäst i aktivitetsfält"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Lossa från aktivitetsfält"</string>
 </resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index f1dbcbc..ca800d9 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Upauzana wa Vipengele vya Ziada"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Fungua programu kama kiputo"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuta ya Mezani"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Aikoni ya programu"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Kichwa cha programu"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Kitufe cha kufunga"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Bandika kwa upauzana"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Bandua kwa upauzana"</string>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 04dfc30..236982a 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"செயல் பட்டிக்கான கூடுதல் விருப்பங்கள்"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ஆப்ஸைக் குமிழாகத் திற"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"டெஸ்க்டாப்"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> வழங்கும் <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ஆப்ஸ் ஐகான்"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ஆப்ஸ் தலைப்பு"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"மூடுவதற்கான பட்டன்"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"செயல்பட்டியில் பின் செய்"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"செயல்பட்டியிலிருந்து அகற்று"</string>
 </resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 516c2f7..d5bc982 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -140,9 +140,15 @@
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string>
     <string name="open_app_as_a_bubble" msgid="6642626287247807473">"యాప్‌ను బబుల్‌లాగా తెరవండి"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్‌}other{మరిన్ని యాప్‌లు}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"డెస్క్‌టాప్"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్‌ఫ్లో"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 04eac38..6767358 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"การดำเนินการเพิ่มเติมของแถบงาน"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"เปิดแอปเป็นบับเบิล"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"เดสก์ท็อป"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ไอคอนแอป"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ชื่อแอป"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"ปุ่มปิด"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ปักหมุดไปยังแถบงาน"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"เลิกปักหมุดจากแถบงาน"</string>
 </resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 89ead25..479a5d3 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -140,9 +140,15 @@
     <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="open_app_as_a_bubble" msgid="6642626287247807473">"Buksan ang app bilang bubble"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
+    <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index f2c42d0..e68056a 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Görev Çubuğu Taşması"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Uygulamayı balon olarak aç"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Uygulama simgesi"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Uygulama başlığı"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Kapat düğmesi"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Çubuğa sabitle"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Çubuktan kaldır"</string>
 </resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 82d8a60..350b23b 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Додаткове меню панелі завдань"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Відкрити додаток у спливаючому вікні"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Комп’ютер"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> з додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Значок додатка"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Назва додатка"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрити\""</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"На панель завдань"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"З панелі завдань"</string>
 </resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 65436ae..3b46f51 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ٹاسک بار اوورفلو"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ایپ کو بطور ببل کھولیں"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"ڈیسک ٹاپ"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"ایپ آئیکن"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"ایپ کا عنوان"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"\'بند کریں\' بٹن"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"ٹاسک بار میں پن کریں"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"ٹاسک بار سے پن ہٹائیں"</string>
 </resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index b761b5d..3f61658 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Vazifalar panelini kengaytirish"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ilovani qalqib chiquvchi oynada ochish"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuter"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Ilova belgisi"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Ilova nomi"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Yopish tugmasi"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Panelga qadash"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Vazifalar panelidan yechib olish"</string>
 </resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 383f915..6f48660 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Trình đơn mục bổ sung trên thanh tác vụ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Mở ứng dụng dưới dạng bong bóng"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Máy tính"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Biểu tượng ứng dụng"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Tên ứng dụng"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Nút đóng"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Ghim vào thanh tác vụ"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Bỏ ghim khỏi thanh tác vụ"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 17d022e..8e8badc 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"任务栏溢出图标"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"以气泡的形式打开应用"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面模式"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"来自“<xliff:g id="APP_NAME">%2$s</xliff:g>”的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"应用图标"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"应用名称"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"“关闭”按钮"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"固定到任务栏"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"从任务栏取消固定"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 47bb6d4..9f5745a 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"工作列溢位"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"在小視窗開啟應用程式"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> 的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"應用程式圖示"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"應用程式名稱"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"關閉按鈕"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"固定至工作列"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"取消固定至工作列"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 58c7bb5..d11cafd 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"工作列溢位"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"以泡泡形式開啟應用程式"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"電腦模式"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"應用程式圖示"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"應用程式標題"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"關閉按鈕"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"固定到工作列"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"從工作列中取消固定"</string>
 </resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 8d0a6db..1d99965 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -139,11 +139,16 @@
     <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Ukuphuphuma Kwetaskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
-    <!-- no translation found for open_app_as_a_bubble (6642626287247807473) -->
+    <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Vula i-app njengebhamuza"</string>
+    <!-- no translation found for quick_switch_pane_title (4677158207760585812) -->
+    <skip />
+    <!-- no translation found for quick_switch_content_description (2851244536728720005) -->
     <skip />
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string>
     <string name="quick_switch_desktop" msgid="8393802056024499749">"Ideskithophu"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+    <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) -->
+    <skip />
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string>
     <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -157,8 +162,6 @@
     <string name="header_app_icon_description" msgid="2184625881433608027">"Isithonjana se-app"</string>
     <string name="header_default_app_title" msgid="8308052350689531566">"Isihloko se-app"</string>
     <string name="header_close_icon_description" msgid="5400033616675911319">"Inkinobho yokuvala"</string>
-    <!-- no translation found for pin_to_taskbar (6607778046321626950) -->
-    <skip />
-    <!-- no translation found for unpin_from_taskbar (2178811773165572676) -->
-    <skip />
+    <string name="pin_to_taskbar" msgid="6607778046321626950">"Phina kutaskbar"</string>
+    <string name="unpin_from_taskbar" msgid="2178811773165572676">"Susa ukuphina i-taskbar"</string>
 </resources>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index e69fa4d..1ce28cf 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -47,6 +47,7 @@
     <string name="wellbeing_provider_pkg" translatable="false"/>
 
     <integer name="max_depth_blur_radius">23</integer>
+    <dimen name="max_depth_blur_radius_enhanced">34dp</dimen>
 
     <!-- If predicted widgets from prediction service are less than this number, additional
     eligible widgets may be added locally by launcher. When set to 0, no widgets will be added
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 36e6902..aa9e824 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -82,9 +82,9 @@
     <dimen name="task_thumbnail_icon_menu_drawable_touch_size">44dp</dimen>
     <dimen name="task_thumbnail_icon_menu_elevation">4dp</dimen>
     <!--  The size of the task thumbnail header  -->
-    <dimen name="task_thumbnail_header_height">30dp</dimen>
-    <dimen name="task_thumbnail_header_margin_edge">18dp</dimen>
-    <dimen name="task_thumbnail_header_margin_between_views">9dp</dimen>
+    <dimen name="task_thumbnail_header_padding_top_bottom">6dp</dimen>
+    <dimen name="task_thumbnail_header_padding_start_end">12dp</dimen>
+    <dimen name="task_thumbnail_header_margin_between_views">8dp</dimen>
     <dimen name="task_thumbnail_header_icon_size">18dp</dimen>
     <dimen name="task_thumbnail_header_round_corner_radius">16dp</dimen>
 
@@ -510,7 +510,8 @@
     <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
 
     <!-- Keyboard Quick Switch -->
-    <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
+    <dimen name="keyboard_quick_switch_border_width">5dp</dimen>
+    <dimen name="keyboard_quick_switch_border_stroke">3dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_height">136dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
@@ -531,8 +532,8 @@
     <dimen name="keyboard_quick_switch_text_button_fade_edge_length">20dp</dimen>
     <dimen name="keyboard_quick_switch_scroll_button_width">36dp</dimen>
     <dimen name="keyboard_quick_switch_scroll_button_height">56dp</dimen>
-    <dimen name="keyboard_quick_switch_scroll_button_horizontal_padding">12dp</dimen>
-    <dimen name="keyboard_quick_switch_scroll_button_vertical_padding">32dp</dimen>
+    <dimen name="keyboard_quick_switch_scroll_button_horizontal_padding">6dp</dimen>
+    <dimen name="keyboard_quick_switch_scroll_button_vertical_padding">16dp</dimen>
     <dimen name="keyboard_quick_switch_scroll_button_corner_radius">18dp</dimen>
 
     <!-- Digital Wellbeing -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 7578bd5..f263f7e 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -345,12 +345,10 @@
     <!-- Accessibility label for quick switch tiles that include information about the tile's position in the parent list [CHAR LIMIT=NONE] -->
     <string name="quick_switch_task_with_position_in_parent"><xliff:g id="task_description" example="Chrome">%1$s</xliff:g>, item <xliff:g id="index_in_parent" example="1">%2$d</xliff:g> of <xliff:g id="total_tasks" example="5">%3$d</xliff:g></string>
 
-    <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content left
-        TODO(b/397975686): Make these translatable when verified by UX. -->
-    <string name="quick_switch_scroll_arrow_left" translatable="false">Scroll left</string>
-    <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content right
-        TODO(b/397975686): Make these translatable when verified by UX. -->
-    <string name="quick_switch_scroll_arrow_right" translatable="false">Scroll right</string>
+    <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content left -->
+    <string name="quick_switch_scroll_arrow_left">Scroll left</string>
+    <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content right -->
+    <string name="quick_switch_scroll_arrow_right">Scroll right</string>
 
     <!-- Strings for bubble bar -->
     <!-- Fallback name for a bubble if it does have a title [CHAR_LIMIT=none] -->
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index aae8a56..954272c 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -92,6 +92,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Log;
 import android.util.Pair;
 import android.util.Size;
 import android.view.CrossWindowBlurListeners;
@@ -182,6 +183,7 @@
  * Manages the opening and closing app transitions from Launcher
  */
 public class QuickstepTransitionManager implements OnDeviceProfileChangeListener {
+    private static final String TAG = "QuickstepTransitionManager";
 
     private static final boolean ENABLE_SHELL_STARTING_SURFACE =
             SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
@@ -1207,7 +1209,7 @@
         mLauncher.removeOnDeviceProfileChangeListener(this);
         SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
         if (BuildConfig.IS_STUDIO_BUILD && !mRegisteredTaskStackChangeListener.isEmpty()) {
-            throw new IllegalStateException("Failed to run onEndCallback created from"
+            Log.e(TAG, "IllegalState: Failed to run onEndCallback created from"
                     + " getActivityLaunchOptions()");
         }
         mRegisteredTaskStackChangeListener.forEach(TaskRestartedDuringLaunchListener::unregister);
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 4d3e3be..cdae9ca 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -166,7 +166,7 @@
         mApp = LauncherAppState.getInstance(this);
         InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile();
         mDeviceProfile = idp.getDeviceProfile(this);
-        mModel = new WidgetsModel();
+        mModel = new WidgetsModel(mApp.getContext());
         mWidgetPickerDataProvider = new WidgetPickerDataProvider(this);
 
         setContentView(R.layout.widget_picker_activity);
@@ -309,8 +309,7 @@
      */
     private void refreshAndBindWidgets() {
         MODEL_EXECUTOR.execute(() -> {
-            LauncherAppState app = LauncherAppState.getInstance(this);
-            mModel.update(app, null);
+            mModel.update(null);
 
             StringCache stringCache = new StringCache();
             stringCache.loadStrings(this);
@@ -321,9 +320,10 @@
             // animation.
             openWidgetsSheet();
             if (mUiSurface != null) {
-                mWidgetPredictionsRequester = new WidgetPredictionsRequester(app.getContext(),
-                        mUiSurface, mModel.getWidgetsByComponentKeyForPicker());
-                mWidgetPredictionsRequester.request(mAddedWidgets, /*listener=*/ this);
+                mWidgetPredictionsRequester = new WidgetPredictionsRequester(
+                        getApplicationContext(), mUiSurface,
+                        mModel.getWidgetsByComponentKeyForPicker());
+                mWidgetPredictionsRequester.request(mAddedWidgets, this);
             }
         });
     }
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
index 1438edf..a9e5145 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
@@ -93,7 +93,7 @@
         }
         if (trampolineCloseChange != null) {
             val trampolineCloseAnimator =
-                createTrampolineCloseAnimator(trampolineCloseChange, transaction)
+                createTrampolineCloseAnimator(trampolineCloseChange, transaction, finishCallback)
             animatorsList.add(trampolineCloseAnimator)
         }
         return animatorsList
@@ -112,7 +112,7 @@
     private fun getTrampolineCloseChange(info: TransitionInfo): Change? {
         if (
             info.changes.size < 2 ||
-                !DesktopModeFlags.ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX.isTrue
+            !DesktopModeFlags.ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX.isTrue
         ) {
             return null
         }
@@ -194,13 +194,22 @@
         )
     }
 
-    private fun createTrampolineCloseAnimator(change: Change, transaction: Transaction): Animator {
+    private fun createTrampolineCloseAnimator(
+        change: Change,
+        transaction: Transaction,
+        onAnimFinish: (Animator) -> Unit,
+    ): Animator {
         return ValueAnimator.ofFloat(1f, 0f).apply {
             duration = 100L
             interpolator = Interpolators.LINEAR
             addUpdateListener { animation ->
                 transaction.setAlpha(change.leash, animation.animatedValue as Float).apply()
             }
+            addListener(
+                onEnd = { animation ->
+                    onAnimFinish(animation)
+                }
+            )
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
index fd71151..3544844 100644
--- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
@@ -32,9 +32,9 @@
 import androidx.annotation.NonNull;
 
 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.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
 import com.android.launcher3.model.data.AppInfo;
@@ -65,8 +65,8 @@
     @Override
     public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
             @NonNull AllAppsList apps) {
-        LauncherAppState app = taskController.getApp();
-        Context context = app.getContext();
+        IconCache iconCache = taskController.getIconCache();
+        Context context = taskController.getContext();
 
         // TODO: remove this
         LauncherPrefs.get(context).put(LAST_PREDICTION_ENABLED, !mTargets.isEmpty());
@@ -84,7 +84,7 @@
             if (si != null) {
                 usersForChangedShortcuts.add(si.getUserHandle());
                 itemInfo = new WorkspaceItemInfo(si, context);
-                app.getIconCache().getShortcutIcon(itemInfo, si);
+                iconCache.getShortcutIcon(itemInfo, si);
             } else {
                 String className = target.getClassName();
                 if (COMPONENT_CLASS_MARKER.equals(className)) {
@@ -96,7 +96,7 @@
                 itemInfo = apps.data.stream()
                         .filter(info -> user.equals(info.user) && cn.equals(info.componentName))
                         .map(ai -> {
-                            app.getIconCache().getTitleAndIcon(ai, mPredictorState.lookupFlag);
+                            iconCache.getTitleAndIcon(ai, mPredictorState.lookupFlag);
                             return ai.makeWorkspaceItem(context);
                         })
                         .findAny()
@@ -107,7 +107,7 @@
                                 return null;
                             }
                             AppInfo ai = new AppInfo(context, lai, user);
-                            app.getIconCache().getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG);
+                            iconCache.getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG);
                             return ai.makeWorkspaceItem(context);
                         });
 
@@ -123,8 +123,7 @@
         FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId, items);
         dataModel.extraItems.put(fci.containerId, fci);
         taskController.bindExtraContainerItems(fci);
-        usersForChangedShortcuts.forEach(
-                u -> dataModel.updateShortcutPinnedState(app.getContext(), u));
+        usersForChangedShortcuts.forEach(u -> dataModel.updateShortcutPinnedState(context, u));
 
         // Save to disk
         mPredictorState.storage.write(context, fci.items);
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 0a4b7c8..da55b40 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -82,7 +82,7 @@
                                 && !widgetsInWorkspace.contains(entry.getValue())
                         ).collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
 
-        Context context = taskController.getApp().getContext();
+        Context context = taskController.getContext();
 
         List<WidgetItem> servicePredictedItems = new ArrayList<>();
         List<String> addedWidgetApps = new ArrayList<>();
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 4c24d95..360210b 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -65,7 +65,7 @@
     private void onLauncherDraw() {
         View view = mLauncher.getDragLayer();
         ViewRootImpl viewRootImpl = view.getViewRootImpl();
-        setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
+        setBaseSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
         view.post(() -> view.getViewTreeObserver().removeOnDrawListener(mOnDrawListener));
     }
 
@@ -127,7 +127,7 @@
             mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
         } else {
             mLauncher.getDragLayer().getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
-            setSurface(null);
+            setBaseSurface(null);
         }
     }
 
@@ -189,7 +189,8 @@
         writer.println(prefix + "DepthController");
         writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
         writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
-        writer.println(prefix + "\tmSurface=" + mSurface);
+        writer.println(prefix + "\tmBaseSurface=" + mBaseSurface);
+        writer.println(prefix + "\tmBaseSurfaceOverride=" + mBaseSurfaceOverride);
         writer.println(prefix + "\tmStateDepth=" + stateDepth.getValue());
         writer.println(prefix + "\tmWidgetDepth=" + widgetDepth.getValue());
         writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
index 2402a28..810fa6f 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
@@ -691,8 +691,11 @@
                         "duration= " +
                         transitionDuration),
                 )
-                controller.get()?.isInDesktopMode = true
-                controller.get()?.notifyTaskbarDesktopModeListenersForEntry(transitionDuration)
+                val controller = controller.get()
+                if (controller != null && !controller.isInDesktopMode) {
+                    controller.isInDesktopMode = true
+                    controller.notifyTaskbarDesktopModeListenersForEntry(transitionDuration)
+                }
             }
         }
 
@@ -704,8 +707,11 @@
                         "duration= " +
                         transitionDuration),
                 )
-                controller.get()?.isInDesktopMode = false
-                controller.get()?.notifyTaskbarDesktopModeListenersForExit(transitionDuration)
+                val controller = controller.get()
+                if (controller != null && controller.isInDesktopMode) {
+                    controller.isInDesktopMode = false
+                    controller.notifyTaskbarDesktopModeListenersForExit(transitionDuration)
+                }
             }
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index 09a8670..aa3feb7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -23,6 +23,7 @@
 
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.BaseContext;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Themes;
 import com.android.quickstep.SystemUiProxy;
 
@@ -32,10 +33,20 @@
         implements SystemShortcut.BubbleActivityStarter {
 
     protected final LayoutInflater mLayoutInflater;
+    private final boolean mIsPrimaryDisplay;
 
-    public BaseTaskbarContext(Context windowContext) {
+    public BaseTaskbarContext(Context windowContext, boolean isPrimaryDisplay) {
         super(windowContext, Themes.getActivityThemeRes(windowContext));
         mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
+        mIsPrimaryDisplay = isPrimaryDisplay;
+    }
+
+    public boolean isTransientTaskbar() {
+        return DisplayController.isTransientTaskbar(this) && mIsPrimaryDisplay;
+    }
+
+    public boolean isPrimaryDisplay() {
+        return mIsPrimaryDisplay;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 15be03a..c49029d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -129,7 +129,9 @@
                         : resources.getDimensionPixelSize(
                                 R.dimen.keyboard_quick_switch_task_view_radius),
                 /* borderWidthPx= */ resources.getDimensionPixelSize(
-                                R.dimen.keyboard_quick_switch_border_width),
+                        R.dimen.keyboard_quick_switch_border_width),
+                /* borderStrokePx= */ resources.getDimensionPixelSize(
+                        R.dimen.keyboard_quick_switch_border_stroke),
                 /* boundsBuilder= */ bounds -> {
                     bounds.set(0, 0, getWidth(), getHeight());
                     return Unit.INSTANCE;
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 5f7a026..b5f2532 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -40,7 +40,6 @@
 import com.android.launcher3.desktop.DesktopAppLaunchTransition;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.GroupTask;
@@ -106,8 +105,7 @@
             boolean hasDesktopTask,
             boolean wasDesktopTaskFilteredOut,
             boolean wasOpenedFromTaskbar) {
-        final boolean isTransientTaskBar = DisplayController.isTransientTaskbar(
-                mControllers.taskbarActivityContext);
+        final boolean isTransientTaskBar = mControllers.taskbarActivityContext.isTransientTaskbar();
         positionView(wasOpenedFromTaskbar, isTransientTaskBar);
 
         // Keep the taskbar unstashed if the KQS is opened.
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 62f546b..e998388 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -225,9 +225,8 @@
         if (isVisible || isPinnedTaskbar) {
             return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar);
         } else {
-            return DisplayController.isTransientTaskbar(mLauncher)
-                    ? TRANSIENT_TASKBAR_TRANSITION_DURATION
-                    : TASKBAR_TO_APP_DURATION;
+            return mControllers.taskbarActivityContext.isTransientTaskbar()
+                    ? TRANSIENT_TASKBAR_TRANSITION_DURATION : TASKBAR_TO_APP_DURATION;
         }
     }
 
@@ -337,7 +336,7 @@
         }
 
         // Persistent features EDU tooltip.
-        if (!DisplayController.isTransientTaskbar(mLauncher)) {
+        if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
             mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
             return;
         }
@@ -360,7 +359,7 @@
         }
 
         // Persistent features EDU tooltip.
-        if (!DisplayController.isTransientTaskbar(mLauncher)) {
+        if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
             return !OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.hasReachedMax(mLauncher);
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index ee5b8d1..33cd759 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -42,8 +42,8 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISMISS_IME;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -487,8 +487,17 @@
         mPropertyHolders.add(
                 new StatePropertyHolder(mHomeButtonAlpha.get(
                         ALPHA_INDEX_KEYGUARD_OR_DISABLE),
-                        flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
-                                && (flags & FLAG_DISABLE_HOME) == 0 && !mContext.isGestureNav()));
+                        flags -> {
+                            /* when the keyguard is visible hide home button. Anytime we are
+                             * occluded we want to show the home button for apps over keyguard.
+                             * however we don't want to show when not occluded/visible.
+                             * (visible false || occluded true) && disable false && not gnav
+                             */
+                            return ((flags & FLAG_KEYGUARD_VISIBLE) == 0
+                                    || (flags & FLAG_KEYGUARD_OCCLUDED) != 0)
+                                    && (flags & FLAG_DISABLE_HOME) == 0
+                                    && !mContext.isGestureNav();
+                        }));
 
         // Recents button
         mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
@@ -870,6 +879,9 @@
         if (predictiveBackThreeButtonNav() && buttonType == BUTTON_BACK) {
             // set up special touch listener for back button to support predictive back
             setBackButtonTouchListener(buttonView, navButtonController);
+            // Set this View clickable, so that NearestTouchFrame.java forwards closeby touches to
+            // this View
+            buttonView.setClickable(true);
         } else {
             buttonView.setOnClickListener(view ->
                     navButtonController.onButtonClick(buttonType, view));
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 2e5bebc..6bd3d85 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -36,7 +36,6 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -217,7 +216,7 @@
                 .getTransientTaskbarIconLayoutBounds();
         float startRadius = mStashedHandleRadius;
 
-        if (DisplayController.isTransientTaskbar(mActivity)) {
+        if (mActivity.isTransientTaskbar()) {
             // Account for the full visual height of the transient taskbar.
             int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
             visualBounds.top -= heightDiff;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6afbebf..e41b2d2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -99,6 +99,7 @@
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.config.FeatureFlags;
@@ -138,6 +139,7 @@
 import com.android.launcher3.taskbar.bubbles.stashing.TransientBubbleStashController;
 import com.android.launcher3.taskbar.customization.TaskbarFeatureEvaluator;
 import com.android.launcher3.taskbar.customization.TaskbarSpecsEvaluator;
+import com.android.launcher3.taskbar.growth.NudgeController;
 import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
 import com.android.launcher3.testing.TestLogging;
@@ -255,7 +257,7 @@
             TaskbarNavButtonController buttonController,
             ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider,
             boolean isPrimaryDisplay, SystemUiProxy sysUiProxy) {
-        super(windowContext);
+        super(windowContext, isPrimaryDisplay);
         mIsPrimaryDisplay = isPrimaryDisplay;
         mNavigationBarPanelContext = navigationBarPanelContext;
         mSysUiProxy = sysUiProxy;
@@ -380,19 +382,13 @@
                 new TaskbarPinningController(this),
                 bubbleControllersOptional,
                 new TaskbarDesktopModeController(this,
-                        DesktopVisibilityController.INSTANCE.get(this)));
+                        DesktopVisibilityController.INSTANCE.get(this)),
+                new NudgeController(this));
 
         mLauncherPrefs = LauncherPrefs.get(this);
         onViewCreated();
     }
 
-    /**
-     * Returns whether this is a primary display.
-     */
-    public boolean isPrimaryDisplay() {
-        return mIsPrimaryDisplay;
-    }
-
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
     public void updateDeviceProfile(DeviceProfile launcherDp) {
         applyDeviceProfile(launcherDp);
@@ -411,7 +407,7 @@
 
     /** Returns whether current taskbar is transient. */
     public boolean isTransientTaskbar() {
-        return DisplayController.isTransientTaskbar(this) && !isPhoneMode();
+        return super.isTransientTaskbar() && !isPhoneMode();
     }
 
     /**
@@ -432,7 +428,7 @@
         mDeviceProfile = originDeviceProfile.toBuilder(this)
                 .withDimensionsOverride(overrideProvider).build();
 
-        if (DisplayController.isTransientTaskbar(this)) {
+        if (isTransientTaskbar()) {
             mTransientTaskbarDeviceProfile = mDeviceProfile;
             mPersistentTaskbarDeviceProfile = mDeviceProfile
                     .toBuilder(this)
@@ -450,7 +446,6 @@
         mNavMode = (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()
                 && !mIsPrimaryDisplay) ? NavigationMode.THREE_BUTTONS
                 : DisplayController.getNavigationMode(this);
-
     }
 
     /** Called when the visibility of the bubble bar changed. */
@@ -661,8 +656,7 @@
         int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_SLIPPERY
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-        boolean watchOutside = DisplayController.isTransientTaskbar(this)
-                || isThreeButtonNav();
+        boolean watchOutside = isTransientTaskbar() || isThreeButtonNav();
         if (watchOutside && !isRunningInTestHarness()) {
             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
@@ -1223,8 +1217,8 @@
                 bubbleControllers.bubbleBarViewController.getBubbleBarWithFlyoutMaximumHeight()
         ).orElse(0);
         int taskbarWindowSize;
-        boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
-                || (enableTaskbarPinning() && !isThreeButtonNav());
+        boolean shouldTreatAsTransient =
+                isTransientTaskbar() || (enableTaskbarPinning() && !isThreeButtonNav());
 
         int extraHeightForTaskbarTooltips = enableCursorHoverStates()
                 ? resources.getDimensionPixelSize(R.dimen.arrow_toast_arrow_height)
@@ -1297,7 +1291,7 @@
      * Applies forcibly show flag to taskbar window iff transient taskbar is unstashed.
      */
     public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
-        if (!DisplayController.isTransientTaskbar(this) || isPhoneMode()) {
+        if (!isTransientTaskbar() || isPhoneMode()) {
             return;
         }
         if (shouldForceShow) {
@@ -1344,7 +1338,7 @@
         mControllers.uiController.startSplitSelection(splitSelectSource);
     }
 
-    boolean areDesktopTasksVisible() {
+    boolean isInDesktopMode() {
         return mControllers != null
                 && mControllers.taskbarDesktopModeController.isInDesktopMode(getDisplayId());
     }
@@ -1360,23 +1354,23 @@
         // TODO: b/316004172, b/343289567: Handle `DesktopTask` and `SplitTask`.
         if (tag instanceof SingleTask singleTask) {
             RemoteTransition remoteTransition =
-                    (areDesktopTasksVisible() && canUnminimizeDesktopTask(
+                    (isInDesktopMode() && canUnminimizeDesktopTask(
                             singleTask.getTask().key.id))
                             ? createDesktopAppLaunchRemoteTransition(AppLaunchType.UNMINIMIZE,
                             Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
                             : null;
-            if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) {
+            if (isInDesktopMode() && mControllers.uiController.isInOverviewUi()) {
                 RunnableList runnableList = recents.launchRunningDesktopTaskView();
                 // Wrapping it in runnable so we post after DW is ready for the app
                 // launch.
                 if (runnableList != null) {
                     runnableList.add(() -> UI_HELPER_EXECUTOR.execute(
                             () -> handleGroupTaskLaunch(singleTask, remoteTransition,
-                                    areDesktopTasksVisible(),
+                                    isInDesktopMode(),
                                     DesktopTaskToFrontReason.TASKBAR_TAP)));
                 }
             } else {
-                handleGroupTaskLaunch(singleTask, remoteTransition, areDesktopTasksVisible(),
+                handleGroupTaskLaunch(singleTask, remoteTransition, isInDesktopMode(),
                         DesktopTaskToFrontReason.TASKBAR_TAP);
             }
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
@@ -1402,7 +1396,7 @@
                     : null;
 
 
-            if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) {
+            if (isInDesktopMode() && mControllers.uiController.isInOverviewUi()) {
                 RunnableList runnableList = recents.launchRunningDesktopTaskView();
                 if (runnableList != null) {
                     runnableList.add(() ->
@@ -1676,7 +1670,7 @@
                                                 .launchAppPair((AppPairIcon) launchingIconView,
                                                         -1 /*cuj*/)));
                     } else {
-                        if (areDesktopTasksVisible()
+                        if (isInDesktopMode()
                                 && mControllers.uiController.isInOverviewUi()) {
                             RunnableList runnableList = recents.launchRunningDesktopTaskView();
                             // Wrapping it in runnable so we post after DW is ready for the app
@@ -1722,7 +1716,7 @@
                     return;
                 }
             }
-            if (areDesktopTasksVisible()
+            if (isInDesktopMode()
                     && DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) {
                 launchDesktopApp(intent, info, displayId);
             } else {
@@ -1887,7 +1881,7 @@
      */
     @VisibleForTesting
     public void unstashTaskbarIfStashed() {
-        if (DisplayController.isTransientTaskbar(this)) {
+        if (isTransientTaskbar()) {
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
         }
     }
@@ -1950,6 +1944,8 @@
                 // Override the alpha updates in the icon alignment animation.
                 allAppsButton.setAlpha(0);
             });
+            alphaOverride.addListener(AnimatorListeners.forSuccessCallback(
+                    () -> allAppsButton.setAlpha(1f)));
             fullAnimation.play(alphaOverride);
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 89cc991..5e02d81 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -30,7 +30,6 @@
 import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
 import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT
 import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT
-import com.android.launcher3.util.DisplayController
 import kotlin.math.min
 
 /** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
@@ -43,7 +42,7 @@
     private val maxPersistentTaskbarHeight =
         context.persistentTaskbarDeviceProfile.taskbarHeight.toFloat()
     var backgroundProgress =
-        if (DisplayController.isTransientTaskbar(context)) {
+        if (context.isTransientTaskbar) {
             PINNING_TRANSIENT
         } else {
             PINNING_PERSISTENT
@@ -102,7 +101,7 @@
 
         fullCornerRadius = context.cornerRadius.toFloat()
         cornerRadius = fullCornerRadius
-        if (!context.areDesktopTasksVisible()) {
+        if (!context.isInDesktopMode()) {
             setCornerRoundness(MAX_ROUNDNESS)
         }
     }
@@ -124,7 +123,7 @@
      * @param cornerRoundness 0 has no round corner, 1 has complete round corner.
      */
     fun setCornerRoundness(cornerRoundness: Float) {
-        if (DisplayController.isTransientTaskbar(context) && !transientBackgroundBounds.isEmpty) {
+        if (context.isTransientTaskbar && !transientBackgroundBounds.isEmpty) {
             return
         }
 
@@ -146,7 +145,7 @@
     /** Draws the background with the given paint and height, on the provided canvas. */
     fun draw(canvas: Canvas) {
         if (isInSetup) return
-        val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
+        val isTransientTaskbar = context.isTransientTaskbar
         canvas.save()
         if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) {
             drawPersistentBackground(canvas)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 58606de..9e15a60 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.growth.NudgeController;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
 import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -67,6 +68,7 @@
     public final TaskbarPinningController taskbarPinningController;
     public final Optional<BubbleControllers> bubbleControllers;
     public final TaskbarDesktopModeController taskbarDesktopModeController;
+    public final NudgeController nudgeController;
 
     @Nullable private LoggableTaskbarController[] mControllersToLog = null;
     @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -115,7 +117,8 @@
             KeyboardQuickSwitchController keyboardQuickSwitchController,
             TaskbarPinningController taskbarPinningController,
             Optional<BubbleControllers> bubbleControllers,
-            TaskbarDesktopModeController taskbarDesktopModeController) {
+            TaskbarDesktopModeController taskbarDesktopModeController,
+            NudgeController nudgeController) {
         this.taskbarActivityContext = taskbarActivityContext;
         this.taskbarDragController = taskbarDragController;
         this.navButtonController = navButtonController;
@@ -143,6 +146,7 @@
         this.taskbarPinningController = taskbarPinningController;
         this.bubbleControllers = bubbleControllers;
         this.taskbarDesktopModeController = taskbarDesktopModeController;
+        this.nudgeController = nudgeController;
     }
 
     /**
@@ -179,6 +183,7 @@
         keyboardQuickSwitchController.init(this);
         taskbarPinningController.init(this, mSharedState);
         taskbarDesktopModeController.init(this, mSharedState);
+        nudgeController.init(this);
 
         mControllersToLog = new LoggableTaskbarController[] {
                 taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -189,6 +194,7 @@
                 voiceInteractionWindowController, taskbarRecentAppsController,
                 taskbarTranslationController, taskbarEduTooltipController,
                 keyboardQuickSwitchController, taskbarPinningController,
+                nudgeController
         };
         mBackgroundRendererControllers = new BackgroundRendererController[] {
                 taskbarDragLayerController, taskbarScrimViewController,
@@ -260,6 +266,7 @@
         mAreAllControllersInitialized = false;
         mSharedState = null;
 
+        taskbarDragController.onDestroy();
         navbarButtonsViewController.onDestroy();
         uiController.onDestroy();
         rotationButtonController.onDestroy();
@@ -280,7 +287,6 @@
         taskbarStashController.onDestroy();
         bubbleControllers.ifPresent(controllers -> controllers.onDestroy());
         taskbarDesktopModeController.onDestroy();
-
         mControllersToLog = null;
         mBackgroundRendererControllers = null;
     }
@@ -344,7 +350,7 @@
         return taskbarActivityContext;
     }
 
-    protected interface LoggableTaskbarController {
+    public interface LoggableTaskbarController {
         void dumpLogs(String prefix, PrintWriter pw);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index 3f6ebe2..b663444 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -35,7 +35,6 @@
 import com.android.launcher3.R
 import com.android.launcher3.popup.ArrowPopup
 import com.android.launcher3.popup.RoundedArrowDrawable
-import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.Themes
 import com.android.launcher3.views.ActivityContext
 import kotlin.math.max
@@ -70,6 +69,8 @@
 
     private lateinit var dividerView: View
     private var horizontalPosition = 0.0f
+    private val taskbarActivityContext: TaskbarActivityContext =
+        ActivityContext.lookupContext(context)
 
     private val popupCornerRadius = Themes.getDialogCornerRadius(context)
     private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
@@ -78,7 +79,8 @@
     private val minPaddingFromScreenEdge =
         resources.getDimension(R.dimen.taskbar_pinning_popup_menu_min_padding_from_screen_edge)
 
-    private var alwaysShowTaskbarOn = !DisplayController.isTransientTaskbar(context)
+    // TODO: add test for isTransientTaskbar & long presses divider and ensures the popup shows up.
+    private var alwaysShowTaskbarOn = !taskbarActivityContext.isTransientTaskbar
     private var didPreferenceChange = false
     private var verticalOffsetForPopupView =
         resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_vertical_margin)
@@ -113,7 +115,7 @@
         }
         alwaysShowTaskbarSwitch.setOnClickListener { view -> (view.parent as View).performClick() }
 
-        if (ActivityContext.lookupContext<TaskbarActivityContext>(context).isGestureNav) {
+        if (taskbarActivityContext.isGestureNav) {
             taskbarSwitchOption.setOnClickListener {
                 alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
                 onClickAlwaysShowTaskbarSwitchOption()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 1b516be..142f458 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -80,7 +80,6 @@
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.views.BubbleTextHolder;
@@ -132,6 +131,14 @@
 
     public void init(TaskbarControllers controllers) {
         mControllers = controllers;
+        mControllers.bubbleControllers.ifPresent(
+                c -> c.bubbleBarViewController.addBubbleBarDropTargets(this));
+    }
+
+    /** Called when the controller is destroyed. */
+    public void onDestroy() {
+        mControllers.bubbleControllers.ifPresent(
+                c -> c.bubbleBarViewController.removeBubbleBarDropTargets(this));
     }
 
     public void setDisallowGlobalDrag(boolean disallowGlobalDrag) {
@@ -463,7 +470,7 @@
             com.android.launcher3.logging.InstanceId launcherInstanceId = instanceIds.second;
 
             intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId);
-            if (DisplayController.isTransientTaskbar(mActivity)) {
+            if (mActivity.isTransientTaskbar()) {
                 // Tell WM Shell to ignore drag events in the provided transient taskbar region.
                 TaskbarDragLayer dragLayer = mControllers.taskbarActivityContext.getDragLayer();
                 int[] locationOnScreen = dragLayer.getLocationOnScreen();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 55ecc37..1e193f6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.util.DimensionUtils;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.TouchController;
 
@@ -108,19 +107,18 @@
 
         if (startAnimation != null) {
             // set taskbar background render animation boolean
-            if (DisplayController.isTransientTaskbar(mActivity)) {
+            if (mActivity.isTransientTaskbar()) {
                 mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true);
             } else {
                 mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true);
             }
 
-            float desiredValue = DisplayController.isTransientTaskbar(mActivity)
+            float desiredValue = mActivity.isTransientTaskbar()
                     ? PINNING_TRANSIENT
                     : PINNING_PERSISTENT;
 
-            float nonDesiredvalue = !DisplayController.isTransientTaskbar(mActivity)
-                    ? PINNING_TRANSIENT
-                    : PINNING_PERSISTENT;
+            float nonDesiredvalue =
+                    !mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT;
 
             ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue(
                     nonDesiredvalue, desiredValue);
@@ -133,9 +131,8 @@
             }));
 
         } else {
-            mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
-                    ? PINNING_TRANSIENT
-                    : PINNING_PERSISTENT);
+            mTaskbarBackgroundProgress.updateValue(
+                    mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT);
         }
 
         mBgTaskbar.value = 1;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index d624413..7a23006 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -155,7 +155,7 @@
     fun maybeShowSwipeEdu() {
         if (
             !isTooltipEnabled ||
-                !DisplayController.isTransientTaskbar(activityContext) ||
+                !activityContext.isTransientTaskbar ||
                 tooltipStep > TOOLTIP_STEP_SWIPE
         ) {
             return
@@ -200,7 +200,7 @@
             suggestionsAnim.supportLightTheme()
             pinningAnim.supportLightTheme()
             handleEduAnimations(listOf(splitscreenAnim, suggestionsAnim, pinningAnim))
-            if (DisplayController.isTransientTaskbar(activityContext)) {
+            if (activityContext.isTransientTaskbar) {
                 splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
                 suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
                 pinningEdu.visibility = if (enableTaskbarPinning()) VISIBLE else GONE
@@ -230,7 +230,7 @@
             // Set up layout parameters.
             content.updateLayoutParams { width = MATCH_PARENT }
             updateLayoutParams<MarginLayoutParams> {
-                if (DisplayController.isTransientTaskbar(activityContext)) {
+                if (activityContext.isTransientTaskbar) {
                     width =
                         resources.getDimensionPixelSize(
                             if (enableTaskbarPinning())
@@ -263,7 +263,7 @@
         // for the original 2 edu steps) as a proxy to needing to show the separate pinning edu
         if (
             !enableTaskbarPinning() ||
-                !DisplayController.isTransientTaskbar(activityContext) ||
+                !activityContext.isTransientTaskbar ||
                 !isTooltipEnabled ||
                 tooltipStep > TOOLTIP_STEP_PINNING ||
                 tooltipStep < TOOLTIP_STEP_FEATURES
@@ -289,7 +289,7 @@
             pinningAnim.supportLightTheme()
             handleEduAnimations(listOf(pinningAnim))
             updateLayoutParams<BaseDragLayer.LayoutParams> {
-                if (DisplayController.isTransientTaskbar(activityContext)) {
+                if (activityContext.isTransientTaskbar) {
                     bottomMargin += activityContext.deviceProfile.taskbarHeight
                 }
                 // Unlike other tooltips, we want to align with taskbar divider rather than center.
@@ -344,7 +344,7 @@
 
             showDisclosureText(eduSubtitle)
             updateLayoutParams<BaseDragLayer.LayoutParams> {
-                if (DisplayController.isTransientTaskbar(activityContext)) {
+                if (activityContext.isTransientTaskbar) {
                     bottomMargin += activityContext.deviceProfile.taskbarHeight
                 }
                 // Unlike other tooltips, we want to align with the all apps button rather than
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index a8ce10f..3af2ab6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -235,8 +235,7 @@
                         context.resources,
                     )
                 val isPinnedTaskbar =
-                    context.deviceProfile.isTaskbarPresent &&
-                        !context.deviceProfile.isTransientTaskbar
+                    context.deviceProfile.isTaskbarPresent && !context.isTransientTaskbar
                 val mandatoryGestureHeight = if (isPinnedTaskbar) contentHeight else gestureHeight
                 provider.insetsSize =
                     getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity, endRotation)
@@ -388,10 +387,7 @@
                 bubbleBarVisible
         ) {
             // Taskbar has some touchable elements, take over the full taskbar area
-            if (
-                controllers.uiController.isInOverviewUi &&
-                    DisplayController.isTransientTaskbar(context)
-            ) {
+            if (controllers.uiController.isInOverviewUi && context.isTransientTaskbar) {
                 val region =
                     controllers.taskbarActivityContext.dragLayer.lastDrawnTransientRect.toRegion()
                 val bubbleBarBounds =
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index bee0997..b5e271d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -17,6 +17,8 @@
 
 import static android.content.Context.RECEIVER_EXPORTED;
 import static android.content.Context.RECEIVER_NOT_EXPORTED;
+import static android.content.pm.PackageManager.FEATURE_PC;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
@@ -26,6 +28,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.taskbar.growth.GrowthConstants.BROADCAST_SHOW_NUDGE;
+import static com.android.launcher3.taskbar.growth.GrowthConstants.GROWTH_NUDGE_PERMISSION;
 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;
@@ -86,6 +89,7 @@
 import com.android.quickstep.util.ContextualSearchInvoker;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.RecentsViewContainer;
+import com.android.server.am.Flags;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.statusbar.phone.BarTransitions;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -166,6 +170,10 @@
     private final SparseArray<DeviceProfile> mExternalDeviceProfiles = new SparseArray<>();
     private StatefulActivity mActivity;
     private RecentsViewContainer mRecentsViewContainer;
+    /** Whether this device is a desktop android device **/
+    private boolean mIsAndroidPC;
+    /** Whether this device supports freeform windows management. Can change dynamically **/
+    private boolean mSupportsFreeformWindowsManagement;
 
     /**
      * Cache a copy here so we can initialize state whenever taskbar is recreated, since
@@ -188,29 +196,29 @@
     private class RecreationListener implements DisplayController.DisplayInfoChangeListener {
         @Override
         public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
+            int displayId = context.getDisplayId();
             if ((flags & CHANGE_DENSITY) != 0) {
-                debugTaskbarManager("onDisplayInfoChanged: Display density changed",
-                        context.getDisplayId());
+                debugTaskbarManager("onDisplayInfoChanged: Display density changed", displayId);
             }
             if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
-                debugTaskbarManager("onDisplayInfoChanged: Navigation mode changed",
-                        context.getDisplayId());
+                debugTaskbarManager("onDisplayInfoChanged: Navigation mode changed", displayId);
             }
             if ((flags & CHANGE_DESKTOP_MODE) != 0) {
                 debugTaskbarManager("onDisplayInfoChanged: Desktop mode changed",
                         context.getDisplayId());
+                handleDisplayUpdatesForPerceptibleTasks();
             }
             if ((flags & CHANGE_TASKBAR_PINNING) != 0) {
-                debugTaskbarManager("onDisplayInfoChanged: Taskbar pinning changed",
-                        context.getDisplayId());
+                debugTaskbarManager("onDisplayInfoChanged: Taskbar pinning changed", displayId);
             }
 
             if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
                     | CHANGE_TASKBAR_PINNING | CHANGE_SHOW_LOCKED_TASKBAR)) != 0) {
-                debugTaskbarManager("onDisplayInfoChanged: Recreating Taskbar!",
-                        context.getDisplayId());
+
                 TaskbarActivityContext taskbarActivityContext = getCurrentActivityContext();
                 if ((flags & CHANGE_SHOW_LOCKED_TASKBAR) != 0) {
+                    debugTaskbarManager("onDisplayInfoChanged: show locked taskbar changed!",
+                            displayId);
                     recreateTaskbars();
                 } else if ((flags & CHANGE_DESKTOP_MODE) != 0) {
                     if (mShouldIgnoreNextDesktopModeChangeFromDisplayController) {
@@ -234,7 +242,7 @@
         recreateTaskbars();
     };
 
-    private final PerceptibleTaskListener mTaskStackListener;
+    private PerceptibleTaskListener mTaskStackListener;
 
     private class PerceptibleTaskListener implements TaskStackChangeListener {
         private ArraySet<Integer> mPerceptibleTasks = new ArraySet<Integer>();
@@ -288,6 +296,14 @@
         public void onTaskRemoved(int taskId) {
             mPerceptibleTasks.remove(taskId);
         }
+
+        public void unregisterListener() {
+            for (Integer taskId : mPerceptibleTasks) {
+                ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false);
+            }
+            TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
+                    mTaskStackListener);
+        }
     }
 
     private final DesktopVisibilityController.TaskbarDesktopModeListener
@@ -297,6 +313,11 @@
                 public void onExitDesktopMode(int duration) {
                     for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) {
                         int displayId = mTaskbars.keyAt(taskbarIndex);
+                        if (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()
+                                && !isDefaultDisplay(displayId)) {
+                            continue;
+                        }
+
                         TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay(
                                 displayId);
                         if (taskbarActivityContext != null
@@ -316,6 +337,11 @@
                 public void onEnterDesktopMode(int duration) {
                     for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) {
                         int displayId = mTaskbars.keyAt(taskbarIndex);
+                        if (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()
+                                && !isDefaultDisplay(displayId)) {
+                            continue;
+                        }
+
                         TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay(
                                 displayId);
                         if (taskbarActivityContext != null) {
@@ -337,7 +363,6 @@
                 }
             };
 
-
     private boolean mUserUnlocked = false;
 
     private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver;
@@ -442,7 +467,7 @@
             mGrowthBroadcastReceiver =
                     new SimpleBroadcastReceiver(
                             mPrimaryWindowContext, UI_HELPER_EXECUTOR, this::showGrowthNudge);
-            mGrowthBroadcastReceiver.register(RECEIVER_EXPORTED,
+            mGrowthBroadcastReceiver.register(null, GROWTH_NUDGE_PERMISSION, RECEIVER_EXPORTED,
                     BROADCAST_SHOW_NUDGE);
         } else {
             mGrowthBroadcastReceiver = null;
@@ -457,7 +482,10 @@
             mTaskbarBroadcastReceiver.register(RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
         });
 
-        if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) {
+        mIsAndroidPC = getPrimaryWindowContext().getPackageManager().hasSystemFeature(FEATURE_PC);
+        mSupportsFreeformWindowsManagement = getFreeformWindowsManagementInfo();
+
+        if (eligibleForPerceptibleTasks()) {
             mTaskStackListener = new PerceptibleTaskListener();
             TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
         } else {
@@ -467,6 +495,30 @@
         debugPrimaryTaskbar("TaskbarManager created");
     }
 
+    private void handleDisplayUpdatesForPerceptibleTasks() {
+        // 1. When desktop mode changes, detect eligibility for perceptible tasks.
+        // 2. When no longer eligible for perceptible tasks, turn off and clean up.
+        mSupportsFreeformWindowsManagement = getFreeformWindowsManagementInfo();
+        if (eligibleForPerceptibleTasks()) {
+            if (mTaskStackListener == null) {
+                mTaskStackListener = new PerceptibleTaskListener();
+                TaskStackChangeListeners.getInstance()
+                        .registerTaskStackListener(mTaskStackListener);
+            }
+        } else {
+            // not eligible for perceptible tasks, so we should unregister the listener
+            if (mTaskStackListener != null) {
+                mTaskStackListener.unregisterListener();
+                mTaskStackListener = null;
+            }
+        }
+    }
+
+    private boolean getFreeformWindowsManagementInfo() {
+        return getPrimaryWindowContext().getPackageManager().hasSystemFeature(
+                FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+    }
+
     private void destroyAllTaskbars() {
         debugPrimaryTaskbar("destroyAllTaskbars");
         for (int i = 0; i < mTaskbars.size(); i++) {
@@ -504,7 +556,7 @@
         debugPrimaryTaskbar("destroyTaskbarForDisplay");
         // TODO: make this code displayId specific
         TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
-        if (ACTION_SHOW_TASKBAR.equals(intent.getAction())) {
+        if (ACTION_SHOW_TASKBAR.equals(intent.getAction()) && taskbar != null) {
             taskbar.showTaskbarFromBroadcast();
         }
     }
@@ -733,8 +785,7 @@
                         displayId);
                 taskbar.updateDeviceProfile(dp);
             }
-            mSharedState.startTaskbarVariantIsTransient =
-                    DisplayController.isTransientTaskbar(taskbar);
+            mSharedState.startTaskbarVariantIsTransient = taskbar.isTransientTaskbar();
             mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
             taskbar.init(mSharedState, duration);
 
@@ -988,12 +1039,12 @@
                     displayId);
             removeAndUnregisterComponentCallbacks(displayId);
 
-            debugTaskbarManager("onDisplayRemoved: destroying Taskbar!", displayId);
-            destroyTaskbarForDisplay(displayId);
-
             debugTaskbarManager("onDisplayRemoved: removing DeviceProfile from map!", displayId);
             removeDeviceProfileFromMap(displayId);
 
+            debugTaskbarManager("onDisplayRemoved: destroying Taskbar!", displayId);
+            destroyTaskbarForDisplay(displayId);
+
             debugTaskbarManager("onDisplayRemoved: removing WindowContext from map!", displayId);
             removeWindowContextFromMap(displayId);
 
@@ -1052,17 +1103,26 @@
         debugPrimaryTaskbar("destroy: unregistering component callbacks");
         removeAndUnregisterComponentCallbacks(getDefaultDisplayId());
         mShutdownReceiver.unregisterReceiverSafely();
-        if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) {
-            for (Integer taskId : mTaskStackListener.mPerceptibleTasks) {
-                ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false);
-            }
+        if (mTaskStackListener != null) {
+            mTaskStackListener.unregisterListener();
         }
-        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
+
         debugPrimaryTaskbar("destroy: destroying all taskbars!");
         destroyAllTaskbars();
         debugPrimaryTaskbar("destroy: finished!");
     }
 
+    private boolean eligibleForPerceptibleTasks() {
+        // Perceptible tasks feature (oom boosting) is eligible for android PC devices, and
+        // other android devices that supports free form windows
+        //
+        // - isAndroidPC is set per device (in this case, desktop devices)
+        // - supportsFreeformWindowsManagement is dynamic, and is to be used for the use-case where
+        // user plugs in their device to external displays
+        return Flags.perceptibleTasks()
+                && (mIsAndroidPC || mSupportsFreeformWindowsManagement);
+    }
+
     public @Nullable TaskbarActivityContext getCurrentActivityContext() {
         return getTaskbarForDisplay(getDefaultDisplayId());
     }
@@ -1168,7 +1228,7 @@
      * @return The {@link TaskbarActivityContext} for the specified display, or
      * {@code null} if no taskbar is associated with that display.
      */
-    private TaskbarActivityContext getTaskbarForDisplay(int displayId) {
+    public TaskbarActivityContext getTaskbarForDisplay(int displayId) {
         return mTaskbars.get(displayId);
     }
 
@@ -1319,7 +1379,6 @@
                         }
                     }
                 } else {
-
                     getCurrentActivityContext().onConfigurationChanged(configDiff);
                 }
                 mOldConfig = new Configuration(newConfig);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 4a7e4f0..bf73f02 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -31,7 +31,6 @@
 
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
-import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 
@@ -93,7 +92,8 @@
             // There is no scrim for the bar in the phone mode.
             return;
         }
-        if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) {
+        boolean isTransient = mActivity.isTransientTaskbar();
+        if (isBubbleBarEnabled() && isTransient) {
             // These scrims aren't used if bubble bar & transient taskbar are active.
             return;
         }
@@ -112,7 +112,7 @@
         boolean showScrimForBubbles = bubblesExpanded
                 && !mTaskbarVisible
                 && isBubbleControllersPresented
-                && !DisplayController.isTransientTaskbar(mActivity)
+                && !mActivity.isTransientTaskbar()
                 && !bubbleControllers.bubbleStashController.isBubblesShowingOnHome();
         return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible()
                 && !isShadeVisible
@@ -122,8 +122,8 @@
     }
 
     private float computeScrimAlpha() {
-        final boolean isPersistentTaskBarVisible =
-                mTaskbarVisible && !DisplayController.isTransientTaskbar(mScrimView.getContext());
+        boolean isTransient = mActivity.isTransientTaskbar();
+        final boolean isPersistentTaskBarVisible = mTaskbarVisible && !isTransient;
         final boolean manageMenuExpanded =
                 (mSysUiStateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
         if (isPersistentTaskBarVisible && manageMenuExpanded) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
index f87c21e..fa35a03 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
@@ -27,7 +27,6 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.SpringAnimationBuilder;
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController;
-import com.android.launcher3.util.DisplayController;
 
 import java.io.PrintWriter;
 
@@ -47,7 +46,7 @@
 
     public TaskbarSpringOnStashController(TaskbarActivityContext context) {
         mContext = context;
-        mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
+        mIsTransientTaskbar = context.isTransientTaskbar();
         mStartVelocityPxPerS = context.getResources()
                 .getDimension(R.dimen.transient_taskbar_stash_spring_velocity_dp_per_s);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 95724ad..5284edd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -346,7 +346,7 @@
                 StashedHandleViewController.ALPHA_INDEX_STASHED);
         mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
 
-        boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
+        boolean isTransientTaskbar = mActivity.isTransientTaskbar();
         boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
         boolean isStashedInAppAuto =
                 isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned();
@@ -367,9 +367,7 @@
 
         // Hide the background while stashed so it doesn't show on fast swipes home
         boolean shouldHideTaskbarBackground = mActivity.isPhoneMode() ||
-                (enableScalingRevealHomeAnimation()
-                        && DisplayController.isTransientTaskbar(mActivity)
-                        && isStashed());
+                (enableScalingRevealHomeAnimation() && isTransientTaskbar && isStashed());
 
         mTaskbarBackgroundAlphaForStash.setValue(shouldHideTaskbarBackground ? 0 : 1);
 
@@ -414,8 +412,7 @@
         if (DisplayController.isPinnedTaskbar(mActivity)) {
             return PINNED_TASKBAR_TRANSITION_DURATION;
         }
-        return DisplayController.isTransientTaskbar(mActivity)
-                ? TRANSIENT_TASKBAR_STASH_DURATION
+        return mActivity.isTransientTaskbar() ? TRANSIENT_TASKBAR_STASH_DURATION
                 : TASKBAR_STASH_DURATION;
     }
 
@@ -509,8 +506,8 @@
      * @see android.view.WindowInsets.Type#systemBars()
      */
     public int getContentHeightToReportToApps() {
-        if (mActivity.isUserSetupComplete() && (mActivity.isPhoneGestureNavMode()
-                || DisplayController.isTransientTaskbar(mActivity))) {
+        boolean isTransient = mActivity.isTransientTaskbar();
+        if (mActivity.isUserSetupComplete() && (mActivity.isPhoneGestureNavMode() || isTransient)) {
             return getStashedHeight();
         }
 
@@ -577,8 +574,7 @@
      */
     public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow,
             boolean delayTaskbarBackground) {
-        if (!DisplayController.isTransientTaskbar(mActivity)
-                || mActivity.isBubbleBarOnPhone()) {
+        if (!mActivity.isTransientTaskbar() || mActivity.isBubbleBarOnPhone()) {
             return;
         }
 
@@ -646,7 +642,7 @@
 
     /** Toggles the Taskbar's stash state. */
     public void toggleTaskbarStash() {
-        if (!DisplayController.isTransientTaskbar(mActivity) || !hasAnyFlag(FLAGS_IN_APP)) return;
+        if (!mActivity.isTransientTaskbar() || !hasAnyFlag(FLAGS_IN_APP)) return;
         updateAndAnimateTransientTaskbar(!hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
     }
 
@@ -697,8 +693,7 @@
         mAnimator = new AnimatorSet();
         addJankMonitorListener(
                 mAnimator, /* expanding= */ !isStashed, /* tag= */ jankTag);
-        boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
-        final float stashTranslation = mActivity.isPhoneMode() || isTransientTaskbar
+        final float stashTranslation = mActivity.isPhoneMode() || mActivity.isTransientTaskbar()
                 ? 0
                 : (mUnstashedHeight - mStashedHeight);
 
@@ -722,7 +717,7 @@
             return;
         }
 
-        if (isTransientTaskbar) {
+        if (mActivity.isTransientTaskbar()) {
             createTransientAnimToIsStashed(mAnimator, isStashed, duration,
                     shouldDelayBackground, animationType);
         } else {
@@ -1144,7 +1139,7 @@
 
         boolean stashForBubbles = hasAnyFlag(FLAG_IN_OVERVIEW)
                 && hasAnyFlag(systemUiStateFlags, SYSUI_STATE_BUBBLES_EXPANDED)
-                && DisplayController.isTransientTaskbar(mActivity);
+                && mActivity.isTransientTaskbar();
         updateStateForFlag(FLAG_STASHED_SYSUI,
                 hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING) || stashForBubbles);
         updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED,
@@ -1174,7 +1169,7 @@
      * <p>Do not stash if a system gesture is started.
      */
     private boolean shouldStashForIme() {
-        if (DisplayController.isTransientTaskbar(mActivity)) {
+        if (mActivity.isTransientTaskbar()) {
             return false;
         }
         // Do not stash if in small screen, with 3 button nav, and in landscape.
@@ -1270,7 +1265,7 @@
      */
     public void setUpTaskbarSystemAction(boolean visible) {
         UI_HELPER_EXECUTOR.execute(() -> {
-            if (!visible || !DisplayController.isTransientTaskbar(mActivity)
+            if (!visible || !mActivity.isTransientTaskbar()
                     || mActivity.isPhoneMode()) {
                 mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR);
                 mIsTaskbarSystemActionRegistered = false;
@@ -1321,7 +1316,7 @@
      *                            If false, attempts to re/start the timeout
      */
     public void updateTaskbarTimeout(boolean isAutohideSuspended) {
-        if (!DisplayController.isTransientTaskbar(mActivity)) {
+        if (!mActivity.isTransientTaskbar()) {
             return;
         }
         if (isAutohideSuspended) {
@@ -1335,9 +1330,7 @@
      * Attempts to start timer to auto hide the taskbar based on time.
      */
     private void tryStartTaskbarTimeout() {
-        if (!DisplayController.isTransientTaskbar(mActivity)
-                || mIsStashed
-                || mEnableBlockingTimeoutDuringTests) {
+        if (!mActivity.isTransientTaskbar() || mIsStashed || mEnableBlockingTimeoutDuringTests) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
index deaf024..df10d24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
@@ -23,7 +23,6 @@
 import com.android.launcher3.touch.SingleAxisSwipeDetector
 import com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE
 import com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL
-import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.TouchController
 import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer
 
@@ -39,7 +38,7 @@
 class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : TouchController {
 
     private val activity: TaskbarActivityContext = controllers.taskbarActivityContext
-    private val enabled = DisplayController.isTransientTaskbar(activity)
+    private val enabled = activity.isTransientTaskbar
     private val swipeDownDetector: SingleAxisSwipeDetector
     private val translationCallback = controllers.taskbarTranslationController.transitionCallback
     /** Interpolator to apply resistance as user swipes down to the bottom of the screen. */
@@ -67,7 +66,7 @@
         val gestureHeight: Int =
             ResourceUtils.getNavbarSize(
                 ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
-                activity.resources
+                activity.resources,
             )
         gestureHeightYThreshold = (activity.deviceProfile.heightPx - gestureHeight).toFloat()
     }
@@ -89,7 +88,7 @@
                         maxTouchDisplacement,
                         0f,
                         maxVisualDisplacement,
-                        displacementInterpolator
+                        displacementInterpolator,
                     )
                 )
                 return false
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 5a5d6d0..13fb296 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -29,7 +29,6 @@
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.SpringAnimationBuilder;
-import com.android.launcher3.util.DisplayController;
 
 import java.io.PrintWriter;
 
@@ -63,7 +62,7 @@
 
     public TaskbarTranslationController(TaskbarActivityContext context) {
         mContext = context;
-        mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
+        mIsTransientTaskbar = mContext.isTransientTaskbar();
         mCallback = new TransitionCallback();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index ea0b81e..061a5a1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -37,7 +37,6 @@
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.taskbar.bubbles.BubbleBarController;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.SplitTask;
 import com.android.quickstep.views.RecentsView;
@@ -116,9 +115,8 @@
      */
     public void hideOverlayWindow() {
         mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
-
-        if (!DisplayController.isTransientTaskbar(mControllers.taskbarActivityContext)
-                || mControllers.taskbarAllAppsController.isOpen()) {
+        boolean isTransientTaskbar = mControllers.taskbarActivityContext.isTransientTaskbar();
+        if (!isTransientTaskbar || mControllers.taskbarAllAppsController.isOpen()) {
             mControllers.taskbarOverlayController.hideWindow();
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 93662cd..b2989cd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -61,7 +61,6 @@
 import com.android.launcher3.taskbar.customization.TaskbarAllAppsButtonContainer;
 import com.android.launcher3.taskbar.customization.TaskbarDividerContainer;
 import com.android.launcher3.uioverrides.PredictedAppIcon;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.util.GroupTask;
@@ -130,7 +129,7 @@
 
     private final int mAllAppsButtonTranslationOffset;
 
-    private final int mNumStaticViews;
+    private int mNumStaticViews;
 
     private Set<GroupTask> mPrevRecentTasks = Collections.emptySet();
     private Set<GroupTask> mPrevOverflowTasks = Collections.emptySet();
@@ -184,8 +183,9 @@
         setWillNotDraw(false);
 
         mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
-        mAllAppsButtonTranslationOffset =  (int) getResources().getDimension(
-                mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(isTransientTaskbar()));
+        mAllAppsButtonTranslationOffset = (int) getResources().getDimension(
+                mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(
+                        mActivityContext.isTransientTaskbar()));
 
         if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
             mTaskbarDividerContainer = new TaskbarDividerContainer(context);
@@ -199,8 +199,6 @@
 
         // TODO: Disable touch events on QSB otherwise it can crash.
         mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
-
-        mNumStaticViews = ENABLE_TASKBAR_RECENTS_LAYOUT_TRANSITION.isTrue() ? addStaticViews() : 0;
     }
 
     /**
@@ -240,7 +238,7 @@
                 enableTaskbarPinning() && !mActivityContext.isThreeButtonNav();
         availableWidth -= iconSize - (int) getResources().getDimension(
                 mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(
-                        forceTransientTaskbarSize || isTransientTaskbar()));
+                        forceTransientTaskbarSize || mActivityContext.isTransientTaskbar()));
         ++additionalIcons;
 
         return Math.floorDiv(availableWidth, iconSize) + additionalIcons;
@@ -370,23 +368,9 @@
         if (!(view.getTag() instanceof CollectionInfo)) {
             mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
         }
-        if (view instanceof FolderIcon fi) {
-            // We should clear FolderInfo's Folder and FolderIcon to avoid memory leak.
-            fi.removeListeners();
-        }
         view.setTag(null);
     }
 
-    /** Loop through all {@link FolderIcon} as child views and clear listeners to avoid leak. */
-    public void removeFolderIconListeners() {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            if (getChildAt(i) instanceof FolderIcon fi) {
-                fi.removeListeners();
-            }
-        }
-    }
-
     /** Inflates/binds the hotseat items and recent tasks to the view. */
     protected void updateItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
         if (mActivityContext.isDestroyed()) return;
@@ -447,6 +431,9 @@
 
     private void updateItemsWithLayoutTransition(
             ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
+        if (mNumStaticViews == 0) {
+            mNumStaticViews = addStaticViews();
+        }
 
         // Skip static views and potential All Apps divider, if they are on the left.
         mNextViewIndex = mIsRtl ? 0 : mNumStaticViews;
@@ -475,7 +462,7 @@
         }
 
         // Recents divider takes priority.
-        if (!mAddedDividerForRecents && !mActivityContext.areDesktopTasksVisible()) {
+        if (!mAddedDividerForRecents && !mActivityContext.isInDesktopMode()) {
             updateAllAppsDivider();
         }
     }
@@ -577,6 +564,9 @@
                 LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
                 hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
                 addView(hotseatView, mNextViewIndex, lp);
+            } else if (hotseatView instanceof FolderIcon fi) {
+                fi.onItemsChanged(false);
+                fi.getFolder().reapplyItemInfo();
             }
 
             // Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
@@ -1098,11 +1088,6 @@
         // Ignore, we just implement Insettable to draw behind system insets.
     }
 
-    private boolean isTransientTaskbar() {
-        return DisplayController.isTransientTaskbar(mActivityContext)
-                && !mActivityContext.isPhoneMode();
-    }
-
     public boolean areIconsVisible() {
         // Consider the overall visibility
         return getVisibility() == VISIBLE;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index a80e2c4..6786aed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -267,9 +267,8 @@
                 : mActivity.getDeviceProfile().taskbarHeight;
 
         mTaskbarIconScaleForStash.updateValue(1f);
-        float pinningValue = DisplayController.isTransientTaskbar(mActivity)
-                ? PINNING_TRANSIENT
-                : PINNING_PERSISTENT;
+        float pinningValue =
+                mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT;
         mTaskbarIconScaleForPinning.updateValue(pinningValue);
         mTaskbarIconTranslationYForPinning.updateValue(pinningValue);
         mTaskbarIconTranslationXForPinning.updateValue(pinningValue);
@@ -394,7 +393,6 @@
         if (enableTaskbarPinning()) {
             mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
         }
-        mTaskbarView.removeFolderIconListeners();
         LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
         mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
     }
@@ -936,7 +934,7 @@
         mOnControllerPreCreateCallback.run();
         DeviceProfile taskbarDp = mActivity.getDeviceProfile();
         Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
-        boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
+        boolean isTransientTaskbar = mActivity.isTransientTaskbar();
 
         float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.taskbarIconSize;
         int borderSpacing = launcherDp.hotseatBorderSpace;
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index c380c8d..c7d42b1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -22,7 +22,6 @@
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
-import com.android.launcher3.util.DisplayController
 import com.android.launcher3.views.BaseDragLayer
 import com.android.systemui.animation.ViewRootSync
 import java.io.PrintWriter
@@ -41,8 +40,7 @@
 class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
     TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
 
-    private val isSeparateBackgroundEnabled =
-        !DisplayController.isTransientTaskbar(context) && !context.isPhoneMode
+    private val isSeparateBackgroundEnabled = !context.isTransientTaskbar && !context.isPhoneMode
     private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
     private val nonTouchableInsetsComputer =
         ViewTreeObserver.OnComputeInternalInsetsListener {
@@ -97,7 +95,7 @@
         separateWindowLayoutParams =
             context.createDefaultWindowLayoutParams(
                 TYPE_APPLICATION_OVERLAY,
-                TEMP_BACKGROUND_WINDOW_TITLE
+                TEMP_BACKGROUND_WINDOW_TITLE,
             )
         separateWindowLayoutParams?.isSystemApplicationOverlay = true
     }
@@ -163,7 +161,7 @@
                 // First add the temporary window, then hide the overlapping taskbar background.
                 context.addWindowView(
                     separateWindowForTaskbarBackground,
-                    separateWindowLayoutParams
+                    separateWindowLayoutParams,
                 );
                 { controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(true) }
             } else {
@@ -179,7 +177,7 @@
                 ViewRootSync.synchronizeNextDraw(
                     separateWindowForTaskbarBackground!!,
                     context.dragLayer,
-                    onWindowsSynchronized
+                    onWindowsSynchronized,
                 )
             }
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 5830095..916b28e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -15,7 +15,9 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
+import static com.android.app.animation.Interpolators.DECELERATED_EASE;
 import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
 import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
 
@@ -35,6 +37,7 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorListeners;
@@ -48,9 +51,11 @@
 public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverlayContext>
         implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
     private final Handler mHandler;
+    private final int mMaxBlurRadius;
 
     private TaskbarAllAppsContainerView mAppsView;
     private float mShiftRange;
+    private int mBlurRadius;
     private @Nullable Runnable mShowOnFullyAttachedToWindowRunnable;
 
     // Initialized in init.
@@ -64,6 +69,8 @@
             int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mHandler = new Handler(Looper.myLooper());
+        mMaxBlurRadius = getResources().getDimensionPixelSize(
+                R.dimen.max_depth_blur_radius_enhanced);
     }
 
     void init(TaskbarAllAppsCallbacks callbacks) {
@@ -99,6 +106,7 @@
         if (!animate) {
             mAllAppsCallbacks.onAllAppsTransitionEnd(true);
             setTranslationShift(TRANSLATION_SHIFT_OPENED);
+            mBlurRadius = mMaxBlurRadius;
             return;
         }
 
@@ -123,6 +131,16 @@
             animation.setViewAlpha(mAppsView, 1 - mToTranslationShift, allAppsFadeInterpolator);
         }
 
+        if (Flags.allAppsBlur()) {
+            Interpolator blurInterpolator = isOpening ? LINEAR : DECELERATED_EASE;
+            animation.addOnFrameListener(a -> {
+                float blurProgress =
+                        isOpening ? a.getAnimatedFraction() : 1 - a.getAnimatedFraction();
+                mBlurRadius =
+                        (int) (mMaxBlurRadius * blurInterpolator.getInterpolation(blurProgress));
+            });
+        }
+
         mAllAppsCallbacks.onAllAppsAnimationPending(animation, isOpening);
     }
 
@@ -219,6 +237,7 @@
         // to pass extra bottom offset to background scrim to fill the bottom gap during predictive
         // back swipe.
         mAppsView.drawOnScrimWithBottomOffset(canvas, getBottomOffsetPx());
+        mActivityContext.getOverlayController().setBackgroundBlurRadius(mBlurRadius);
         super.dispatchDraw(canvas);
     }
 
@@ -230,9 +249,13 @@
 
     @Override
     protected int getScrimColor(Context context) {
-        return mActivityContext.getDeviceProfile().isPhone
-                ? Themes.getAttrColor(context, R.attr.allAppsScrimColor)
-                : context.getColor(R.color.widgets_picker_scrim);
+        if (!mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) {
+            return Themes.getAttrColor(context, R.attr.allAppsScrimColor);
+        }
+        if (Flags.allAppsBlur()) {
+            return Themes.getAttrColor(context, R.attr.allAppsScrimColorOverBlur);
+        }
+        return context.getResources().getColor(R.color.widgets_picker_scrim);
     }
 
     @Override
@@ -254,6 +277,7 @@
     public void onDeviceProfileChanged(DeviceProfile dp) {
         setShiftRange(dp.allAppsShiftRange);
         setTranslationShift(TRANSLATION_SHIFT_OPENED);
+        mBlurRadius = mMaxBlurRadius;
     }
 
     private void setShiftRange(float shiftRange) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 52f7176..f1ccd39 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
-import com.android.launcher3.util.DisplayController;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 import java.util.Optional;
@@ -90,7 +89,7 @@
     }
 
     private void setUpTaskbarStashing() {
-        if (DisplayController.isTransientTaskbar(mContext)) {
+        if (mContext.isTransientTaskbar()) {
             mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, true);
             mTaskbarStashController.applyState();
         }
@@ -103,7 +102,7 @@
             AbstractFloatingView.closeOpenContainer(
                     mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
 
-            if (DisplayController.isTransientTaskbar(mContext)) {
+            if (mContext.isTransientTaskbar()) {
                 mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
                 mTaskbarStashController.applyState();
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt
index 383f4d2..24e7d99 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt
@@ -60,8 +60,6 @@
 
     override fun onDrop(dragObject: DropTarget.DragObject, options: DragOptions) {
         val itemInfo = dragObject.dragInfo ?: return
-        // TODO(b/397459664) : fix task bar icon animation after drop
-        // TODO(b/397459664) : update bubble bar location
         bubbleBarDragListener.onLauncherItemDroppedOverBubbleBarDragZone(
             bubbleBarLocation,
             itemInfo,
@@ -77,8 +75,6 @@
     }
 
     override fun onDragExit(dragObject: DropTarget.DragObject) {
-        // TODO(b/397459664) : fix the issue for no bubbles, when moving task bar icon out of
-        // the bubble bar drag zone drag ends and swipes gesture swipes the overview
         if (!isShowingDropTarget) return
         isShowingDropTarget = false
         bubbleBarDragListener.onLauncherItemDraggedOutsideBubbleBarDropZone()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 277dbbf..7fb6480 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -41,15 +41,16 @@
 import androidx.annotation.Nullable;
 
 import com.android.app.animation.Interpolators;
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.launcher3.taskbar.TaskbarDragController;
 import com.android.launcher3.taskbar.TaskbarInsetsController;
 import com.android.launcher3.taskbar.TaskbarSharedState;
 import com.android.launcher3.taskbar.TaskbarStashController;
@@ -144,6 +145,7 @@
         @Override
         public void onLauncherItemDroppedOverBubbleBarDragZone(@NonNull BubbleBarLocation location,
                 @NonNull ItemInfo itemInfo) {
+            AbstractFloatingView.closeAllOpenViews(mActivity);
             if (itemInfo instanceof WorkspaceItemInfo) {
                 ShortcutInfo shortcutInfo = ((WorkspaceItemInfo) itemInfo).getDeepShortcutInfo();
                 if (shortcutInfo != null) {
@@ -193,13 +195,13 @@
     private boolean mShouldShowEducation;
     public boolean mOverflowAdded;
     private boolean mIsLocationUpdatedForDropTarget = false;
+    private boolean mWasStashedBeforeEnteringBubbleDragZone = false;
 
     private BubbleBarViewAnimator mBubbleBarViewAnimator;
     private final FrameLayout mBubbleBarContainer;
     private BubbleBarFlyoutController mBubbleBarFlyoutController;
     private BubbleBarPinController mBubbleBarPinController;
     private TaskbarSharedState mTaskbarSharedState;
-    private TaskbarDragController mTaskbarDragController;
     private final BubbleBarLocationDropTarget mBubbleBarLeftDropTarget;
     private final BubbleBarLocationDropTarget mBubbleBarRightDropTarget;
     private final TimeSource mTimeSource = System::currentTimeMillis;
@@ -236,7 +238,6 @@
     /** Initializes controller. */
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
             TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
-        mTaskbarDragController = controllers.taskbarDragController;
         mTaskbarSharedState = controllers.getSharedState();
         mBubbleStashController = bubbleControllers.bubbleStashController;
         mBubbleBarController = bubbleControllers.bubbleBarController;
@@ -273,7 +274,7 @@
                         mBoundsChangeListener.onBoundsChanged();
                     }
                 });
-        float pinningValue = DisplayController.isTransientTaskbar(mActivity)
+        float pinningValue = mActivity.isTransientTaskbar()
                 ? PINNING_TRANSIENT
                 : PINNING_PERSISTENT;
         mBubbleBarPinning.updateValue(pinningValue);
@@ -338,8 +339,18 @@
                 mBubbleBarController.updateBubbleBarLocation(location, source);
             }
         };
-        mTaskbarDragController.addDropTarget(mBubbleBarLeftDropTarget);
-        mTaskbarDragController.addDropTarget(mBubbleBarRightDropTarget);
+    }
+
+    /** Adds bubble bar locations drop zones to the drag controller. */
+    public void addBubbleBarDropTargets(DragController<?> dragController) {
+        dragController.addDropTarget(mBubbleBarLeftDropTarget);
+        dragController.addDropTarget(mBubbleBarRightDropTarget);
+    }
+
+    /** Removes bubble bar locations drop zones to the drag controller. */
+    public void removeBubbleBarDropTargets(DragController<?> dragController) {
+        dragController.removeDropTarget(mBubbleBarLeftDropTarget);
+        dragController.removeDropTarget(mBubbleBarRightDropTarget);
     }
 
     /** Returns animated float property responsible for pinning transition animation. */
@@ -617,14 +628,30 @@
      * updated.
      */
     public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation bubbleBarLocation) {
+        Log.w("BBAnimation", "onDragItemOverBubbleBarDragZone()");
         mBarView.showDropTarget(/* isDropTarget = */ true);
         boolean isRtl = mBarView.isLayoutRtl();
         mIsLocationUpdatedForDropTarget = getBubbleBarLocation().isOnLeft(isRtl)
                 != bubbleBarLocation.isOnLeft(isRtl);
-        if (mIsLocationUpdatedForDropTarget) {
-            animateBubbleBarLocation(bubbleBarLocation);
-        }
-        if (!hasBubbles()) {
+        mWasStashedBeforeEnteringBubbleDragZone = hasBubbles()
+            && mBubbleStashController.isStashed();
+        if (mWasStashedBeforeEnteringBubbleDragZone) {
+            if (mIsLocationUpdatedForDropTarget) {
+                // bubble bar is stashed an location updated
+                //TODO(b/399678274) add animation
+                mBubbleStashController.showBubbleBarImmediate();
+                animateBubbleBarLocation(bubbleBarLocation);
+            } else {
+                // bubble bar is stashed and location the same - just un-stash
+                mBubbleStashController.showBubbleBar(/* expandBubbles = */ false);
+            }
+        } else if (hasBubbles()) {
+            if (mIsLocationUpdatedForDropTarget) {
+                // bubble bar has bubbles and location is changed - animate bar to the opposite side
+                animateBubbleBarLocation(bubbleBarLocation);
+            }
+        } else {
+            // bubble bar has no bubbles flow just show the empty drop target
             mBubbleBarPinController.showDropTarget(bubbleBarLocation);
         }
     }
@@ -644,12 +671,27 @@
      * mode and reset the value returned from {@link #isLocationUpdatedForDropTarget()} to false.
      */
     public void onItemDraggedOutsideBubbleBarDropZone() {
+        Log.w("BBAnimation", "onItemDraggedOutsideBubbleBarDropZone()");
         mBarView.showDropTarget(/* isDropTarget = */ false);
-        if (mIsLocationUpdatedForDropTarget) {
-            animateBubbleBarLocation(getBubbleBarLocation());
+        if (mWasStashedBeforeEnteringBubbleDragZone) {
+            if (mIsLocationUpdatedForDropTarget) {
+                // bubble bar was stashed and location updated
+                //TODO(b/399678274) add animation
+                animateBubbleBarLocation(getBubbleBarLocation());
+                mBubbleStashController.stashBubbleBarImmediate();
+            } else {
+                // bubble bar was stashed and location the same - just stash it back
+                mBubbleStashController.stashBubbleBar();
+            }
+        } else if (hasBubbles()) {
+            if (mIsLocationUpdatedForDropTarget) {
+                // bubble bar has bubbles and location was changed - return to the original location
+                animateBubbleBarLocation(getBubbleBarLocation());
+            }
         }
         mBubbleBarPinController.hideDropTarget();
         mIsLocationUpdatedForDropTarget = false;
+        mWasStashedBeforeEnteringBubbleDragZone = false;
     }
 
     /**
@@ -657,9 +699,11 @@
      * The controller will hide the drop target if there are no bubbles and exit drop target mode.
      */
     public void onItemDroppedInBubbleBarDragZone() {
+        Log.w("BBAnimation", "onItemDroppedInBubbleBarDragZone()");
         mBarView.showDropTarget(/* isDropTarget = */ false);
         mBubbleBarPinController.hideDropTarget();
         mIsLocationUpdatedForDropTarget = false;
+        mWasStashedBeforeEnteringBubbleDragZone = false;
     }
 
     /**
@@ -1356,20 +1400,18 @@
     /** Called when the controller is destroyed. */
     public void onDestroy() {
         adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false);
-        mTaskbarDragController.removeDropTarget(mBubbleBarLeftDropTarget);
-        mTaskbarDragController.removeDropTarget(mBubbleBarRightDropTarget);
     }
 
     /**
      * Removes the bubble from the bubble bar and notifies sysui that the bubble should move to
      * full screen.
      */
-    public void moveBubbleToFullscreen(@NonNull BubbleView bubbleView) {
+    public void moveDraggedBubbleToFullscreen(@NonNull BubbleView bubbleView, Point dropLocation) {
         if (bubbleView.getBubble() == null) {
             return;
         }
         String key = bubbleView.getBubble().getKey();
-        mSystemUiProxy.moveBubbleToFullscreen(key);
+        mSystemUiProxy.moveDraggedBubbleToFullscreen(key, dropLocation);
         onBubbleDismissed(bubbleView);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index f77b934..3df10c0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar.bubbles;
 
 import android.annotation.SuppressLint;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -231,13 +232,14 @@
             }
 
             @Override
-            void onDragEnd() {
+            void onDragEnd(float x, float y) {
                 mBubbleBarController.updateBubbleBarLocation(getBubbleBarLocationDuringDrag(),
                         BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
                 if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) {
                     mDropTargetManager.onDragEnded();
                     if (mBubbleDragZoneChangedListener.isDraggedToFullscreen()) {
-                        mBubbleBarViewController.moveBubbleToFullscreen(bubbleView);
+                        mBubbleBarViewController.moveDraggedBubbleToFullscreen(
+                                bubbleView, new Point((int) x, (int) y));
                     }
                 } else {
                     mBubblePinController.setListener(null);
@@ -329,7 +331,7 @@
             }
 
             @Override
-            void onDragEnd() {
+            void onDragEnd(float x, float y) {
                 // Make sure to update location as the first thing. Pivot update causes a relayout
                 mBubbleBarController.updateBubbleBarLocation(getBubbleBarLocationDuringDrag(),
                         BubbleBarLocation.UpdateSource.DRAG_BAR);
@@ -428,7 +430,7 @@
         /**
          * Called when the dragging interaction has ended and all the animations have completed
          */
-        abstract void onDragEnd();
+        abstract void onDragEnd(float x, float y);
 
         /**
          * Called when the dragged bubble is released outside of the dismiss target area and will
@@ -579,7 +581,7 @@
             Runnable onComplete = () -> {
                 mActivity.setTaskbarWindowFullscreen(false);
                 cleanUp(view);
-                onDragEnd();
+                onDragEnd(event.getRawX(), event.getRawY());
             };
 
             if (mBubbleDismissController.handleTouchEvent(event)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index 75bf937..ac87b5e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -36,6 +36,8 @@
 import androidx.core.animation.ArgbEvaluator
 import com.android.launcher3.R
 import com.android.launcher3.popup.RoundedArrowDrawable
+import com.android.wm.shell.shared.TypefaceUtils
+import com.android.wm.shell.shared.TypefaceUtils.Companion.setTypeface
 import kotlin.math.min
 
 /** The flyout view used to notify the user of a new bubble notification. */
@@ -163,6 +165,9 @@
         LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true)
         id = R.id.bubble_bar_flyout_view
 
+        setTypeface(title, TypefaceUtils.FontFamily.GSF_LABEL_LARGE)
+        setTypeface(message, TypefaceUtils.FontFamily.GSF_BODY_MEDIUM)
+
         val ta = context.obtainStyledAttributes(intArrayOf(android.R.attr.dialogCornerRadius))
         cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat()
         ta.recycle()
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 4932654..bb2acd6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -32,7 +32,6 @@
 import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
 import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.TaskbarViewCallbacks
-import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
@@ -69,7 +68,7 @@
             )
         backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
         setIconDrawable(drawable)
-        if (!DisplayController.isTransientTaskbar(context)) {
+        if (!activityContext.isTransientTaskbar) {
             setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
         }
         setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index d5f72d5..060ce46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -26,7 +26,6 @@
 import com.android.launcher3.Utilities.dpToPx
 import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.TaskbarViewCallbacks
-import com.android.launcher3.util.DisplayController
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
 
@@ -52,7 +51,7 @@
         backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
         val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
         setIconDrawable(drawable)
-        if (!DisplayController.isTransientTaskbar(context)) {
+        if (!activityContext.isTransientTaskbar) {
             setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
index f130d29..a14c5a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
@@ -19,7 +19,6 @@
 import com.android.launcher3.Flags.enableRecentsInTaskbar
 import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
 import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.launcher3.util.DisplayController
 
 /** Evaluates all the features taskbar can have. */
 class TaskbarFeatureEvaluator
@@ -36,7 +35,7 @@
         get() = enableTaskbarPinning() || isRecentsEnabled
 
     val isTransient: Boolean
-        get() = DisplayController.isTransientTaskbar(taskbarActivityContext)
+        get() = taskbarActivityContext.isTransientTaskbar
 
     val isLandscape: Boolean
         get() = taskbarActivityContext.deviceProfile.isLandscape
diff --git a/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java b/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java
index 78ef152..7d760fc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java
+++ b/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java
@@ -24,5 +24,13 @@
      */
     public static final String BROADCAST_SHOW_NUDGE =
             "com.android.launcher3.growth.BROADCAST_SHOW_NUDGE";
+
+    /**
+     * For filtering package of broadcast intent received.
+     */
+    public static final String GROWTH_NUDGE_PERMISSION =
+            "com.android.growth.permission.GROWTH_NUDGE_PERMISSION"
+                    + " android:protectionLevel=\"signature|preinstalled\"";
+
     private GrowthConstants() {}
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt b/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt
new file mode 100644
index 0000000..04e41bc
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2025 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.growth
+
+import android.content.Context
+import com.android.launcher3.Utilities
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarControllers
+import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.views.ActivityContext
+import java.io.PrintWriter
+
+/** Controls nudge lifecycles. */
+class NudgeController(context: Context) : LoggableTaskbarController {
+
+    protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+
+    private val isNudgeEnabled: Boolean
+        get() {
+            return !Utilities.isRunningInTestHarness() &&
+                !activityContext.isPhoneMode &&
+                !activityContext.isTinyTaskbar
+        }
+
+    private lateinit var controllers: TaskbarControllers
+
+    fun init(controllers: TaskbarControllers) {
+        this.controllers = controllers
+    }
+
+    fun maybeShow(payload: NudgePayload) {
+        if (!isNudgeEnabled || !DisplayController.isTransientTaskbar(activityContext)) {
+            return
+        }
+        // TODO: b/398033012 - create and show nudge view based on the payload.
+    }
+
+    /** Closes the current [nudgeView]. */
+    fun hide() {
+        // TODO: b/398033012 - hide the nudge view.
+    }
+
+    override fun dumpLogs(prefix: String?, pw: PrintWriter?) {
+        pw?.println(prefix + "NudgeController:")
+        pw?.println("$prefix\tisNudgeEnabled=$isNudgeEnabled")
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
index bbf08bf..844f1af 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
@@ -194,6 +194,7 @@
                 event.offsetLocation(mTouchingChild.getWidth() / 2 - x,
                         mTouchingChild.getHeight() / 2 - y);
                 return mTouchingChild.getVisibility() == VISIBLE
+                        && mTouchingChild.isAttachedToWindow()
                         && mTouchingChild.dispatchTouchEvent(event);
             }
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 55bb0f9..dd91d17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -55,7 +55,7 @@
             Context windowContext,
             TaskbarActivityContext taskbarContext,
             TaskbarControllers controllers) {
-        super(windowContext);
+        super(windowContext, taskbarContext.isPrimaryDisplay());
         mTaskbarContext = taskbarContext;
         mOverlayController = controllers.taskbarOverlayController;
         mDragController = new TaskbarDragController(this);
@@ -67,6 +67,11 @@
         onViewCreated();
     }
 
+    /** Called when the controller is destroyed. */
+    public void onDestroy() {
+        mDragController.onDestroy();
+    }
+
     public @Nullable TaskbarSearchSessionController getSearchSessionController() {
         return mSearchSessionController;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index 79cb748..675d55b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -26,8 +26,12 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.AttachedSurfaceControl;
 import android.view.Gravity;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
@@ -36,8 +40,10 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
+import com.android.launcher3.R;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.systemui.shared.system.BlurUtils;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
@@ -52,12 +58,14 @@
  */
 public final class TaskbarOverlayController {
 
+    private static final String TAG = "TaskbarOverlayController";
     private static final String WINDOW_TITLE = "Taskbar Overlay";
 
     private final TaskbarActivityContext mTaskbarContext;
     private final Context mWindowContext;
     private final TaskbarOverlayProxyView mProxyView;
     private final LayoutParams mLayoutParams;
+    private final int mMaxBlurRadius;
 
     private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
@@ -88,6 +96,8 @@
     private DeviceProfile mLauncherDeviceProfile;
     private @Nullable TaskbarOverlayContext mOverlayContext;
     private TaskbarControllers mControllers; // Initialized in init.
+    // True if we have alerted surface flinger of an expensive call for blur.
+    private boolean mInEarlyWakeUp;
 
     public TaskbarOverlayController(
             TaskbarActivityContext taskbarContext, DeviceProfile launcherDeviceProfile) {
@@ -96,6 +106,8 @@
         mProxyView = new TaskbarOverlayProxyView();
         mLayoutParams = createLayoutParams();
         mLauncherDeviceProfile = launcherDeviceProfile;
+        mMaxBlurRadius = mTaskbarContext.getResources().getDimensionPixelSize(
+                R.dimen.max_depth_blur_radius_enhanced);
     }
 
     /** Initialize the controller. */
@@ -150,9 +162,13 @@
     /** Destroys the controller and any overlay window if present. */
     public void onDestroy() {
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
-        Optional.ofNullable(mOverlayContext)
-                .map(c -> c.getSystemService(WindowManager.class))
-                .ifPresent(m -> m.removeViewImmediate(mOverlayContext.getDragLayer()));
+        Optional.ofNullable(mOverlayContext).ifPresent(c -> {
+            c.onDestroy();
+            WindowManager wm = c.getSystemService(WindowManager.class);
+            if (wm != null) {
+                wm.removeViewImmediate(mOverlayContext.getDragLayer());
+            }
+        });
         mOverlayContext = null;
     }
 
@@ -197,6 +213,65 @@
     }
 
     /**
+     * Sets the blur radius for the overlay window.
+     *
+     * @param radius the blur radius in pixels. This will automatically change to {@code 0} if blurs
+     *               are unsupported on the device.
+     */
+    public void setBackgroundBlurRadius(int radius) {
+        if (!Flags.allAppsBlur()) {
+            return;
+        }
+        if (!BlurUtils.supportsBlursOnWindows()) {
+            Log.d(TAG, "setBackgroundBlurRadius: not supported, setting to 0");
+            radius = 0;
+            // intentionally falling through in case a non-0 blur was previously set.
+        }
+        if (mOverlayContext == null) {
+            Log.w(TAG, "setBackgroundBlurRadius: no overlay context");
+            return;
+        }
+        TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
+        if (dragLayer == null) {
+            Log.w(TAG, "setBackgroundBlurRadius: no drag layer");
+            return;
+        }
+        ViewRootImpl dragLayerViewRoot = dragLayer.getViewRootImpl();
+        if (dragLayerViewRoot == null) {
+            Log.w(TAG, "setBackgroundBlurRadius: dragLayerViewRoot is null");
+            return;
+        }
+        AttachedSurfaceControl rootSurfaceControl = dragLayer.getRootSurfaceControl();
+        if (rootSurfaceControl == null) {
+            Log.w(TAG, "setBackgroundBlurRadius: rootSurfaceControl is null");
+            return;
+        }
+        SurfaceControl surfaceControl = dragLayerViewRoot.getSurfaceControl();
+        if (surfaceControl == null || !surfaceControl.isValid()) {
+            Log.w(TAG, "setBackgroundBlurRadius: surfaceControl is null or invalid");
+            return;
+        }
+        Log.v(TAG, "setBackgroundBlurRadius: " + radius);
+        SurfaceControl.Transaction transaction =
+                new SurfaceControl.Transaction().setBackgroundBlurRadius(surfaceControl, radius);
+
+        // Set early wake-up flags when we know we're executing an expensive operation, this way
+        // SurfaceFlinger will adjust its internal offsets to avoid jank.
+        boolean wantsEarlyWakeUp = radius > 0 && radius < mMaxBlurRadius;
+        if (wantsEarlyWakeUp && !mInEarlyWakeUp) {
+            Log.d(TAG, "setBackgroundBlurRadius: setting early wakeup");
+            transaction.setEarlyWakeupStart();
+            mInEarlyWakeUp = true;
+        } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) {
+            Log.d(TAG, "setBackgroundBlurRadius: clearing early wakeup");
+            transaction.setEarlyWakeupEnd();
+            mInEarlyWakeUp = false;
+        }
+
+        rootSurfaceControl.applyTransactionOnDraw(transaction);
+    }
+
+    /**
      * Proxy view connecting taskbar drag layer to the overlay window.
      *
      * Overlays are in a separate window and has its own drag layer, but this proxy lets its views
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index 669850c..41694ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -147,7 +146,7 @@
      * 2) Sets tappableInsets bottom inset to 0.
      */
     private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
-        if (!DisplayController.isTransientTaskbar(mContainer)) {
+        if (!mContainer.isTransientTaskbar()) {
             return oldInsets;
         }
         WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index cd0a4f3..806b8ab 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -86,6 +86,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
@@ -226,6 +227,7 @@
 
 public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
         SystemShortcut.BubbleActivityStarter {
+    private static final String TAG = "QuickstepLauncher";
     private static final boolean TRACE_LAYOUTS =
             SystemProperties.getBoolean("persist.debug.trace_layouts", false);
     private static final String TRACE_RELAYOUT_CLASS =
@@ -561,20 +563,35 @@
 
     @Override
     public void onDestroy() {
+        // wrap non-trivial clean up blocks in try-catch to avoid stopping clean up of rest of
+        // objects
+
         if (mAppTransitionManager != null) {
-            mAppTransitionManager.onActivityDestroyed();
+            try {
+                mAppTransitionManager.onActivityDestroyed();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to destroy mAppTransitionManager", e);
+            }
         }
         mAppTransitionManager = null;
         mIsPredictiveBackToHomeInProgress = false;
 
         if (mUnfoldTransitionProgressProvider != null) {
-            SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
-            mUnfoldTransitionProgressProvider.destroy();
+            try {
+                SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
+                mUnfoldTransitionProgressProvider.destroy();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to destroy mUnfoldTransitionProgressProvider", e);
+            }
         }
 
         OverviewComponentObserver.INSTANCE.get(this)
                 .removeOverviewChangeListener(mOverviewChangeListener);
-        mTISBindHelper.onDestroy();
+        try {
+            mTISBindHelper.onDestroy();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to destroy mTISBindHelper", e);
+        }
 
         if (mLauncherUnfoldAnimationController != null) {
             mLauncherUnfoldAnimationController.onDestroy();
@@ -584,15 +601,22 @@
             mSplitSelectStateController.onDestroy();
         }
 
-        RecentsView recentsView = getOverviewPanel();
-        if (recentsView != null) {
-            recentsView.destroy();
+        try {
+            RecentsView recentsView = getOverviewPanel();
+            if (recentsView != null) {
+                recentsView.destroy();
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to destroy RecentsView", e);
         }
 
-        super.onDestroy();
-        mHotseatPredictionController.destroy();
-        if (mViewCapture != null) mViewCapture.close();
-        removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
+        try {
+            super.onDestroy();
+        } finally { // trivial close operations in finally.
+            mHotseatPredictionController.destroy();
+            if (mViewCapture != null) mViewCapture.close();
+            removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index b27c6e8..54b4fa2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -23,6 +23,7 @@
 
 import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
@@ -153,7 +154,7 @@
         return new PageAlphaProvider(DECELERATE_2) {
             @Override
             public float getPageAlpha(int pageIndex) {
-                return launcher.getDeviceProfile().isTablet
+                return isWorkspaceVisible(launcher.getDeviceProfile())
                         ? superPageAlphaProvider.getPageAlpha(pageIndex)
                         : 0;
             }
@@ -163,13 +164,17 @@
     @Override
     public int getVisibleElements(Launcher launcher) {
         int elements = ALL_APPS_CONTENT | FLOATING_SEARCH_BAR;
-        // When All Apps is presented on a bottom sheet, HOTSEAT_ICONS are visible.
-        if (launcher.getDeviceProfile().isTablet) {
+        if (isWorkspaceVisible(launcher.getDeviceProfile())) {
             elements |= HOTSEAT_ICONS;
         }
         return elements;
     }
 
+    private static boolean isWorkspaceVisible(DeviceProfile deviceProfile) {
+        // Currently we hide the workspace with the all apps blur flag for simplicity.
+        return deviceProfile.isTablet && !Flags.allAppsBlur();
+    }
+
     @Override
     public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) {
         return 0;
@@ -201,8 +206,12 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
-        return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
-                ? launcher.getResources().getColor(R.color.widgets_picker_scrim)
-                : Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
+        if (!launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
+            return Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
+        }
+        if (Flags.allAppsBlur()) {
+            return Themes.getAttrColor(launcher, R.attr.allAppsScrimColorOverBlur);
+        }
+        return launcher.getResources().getColor(R.color.widgets_picker_scrim);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 963504f..3170df9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -17,10 +17,12 @@
 
 import static com.android.app.animation.Interpolators.DECELERATE_2;
 import static com.android.launcher3.Flags.enableDesktopExplodedView;
+import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur;
 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.SystemProperties;
 
@@ -35,6 +37,7 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.BlurUtils;
 
 /**
  * Definition for overview state
@@ -158,7 +161,9 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
-        return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
+        return enableOverviewBackgroundWallpaperBlur() && BlurUtils.supportsBlursOnWindows()
+                ? Color.TRANSPARENT
+                : Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 7574c7f..168b856 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -136,6 +136,7 @@
 import com.android.launcher3.util.WindowBounds;
 import com.android.quickstep.GestureState.GestureEndTarget;
 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
+import com.android.quickstep.fallback.window.RecentsWindowFlags;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -903,7 +904,9 @@
     }
 
     public Intent getLaunchIntent() {
-        return mGestureState.getOverviewIntent();
+        // todo differentiate intent based on if we are on home or in app for overview in window
+        boolean useHomeIntentForWindow = RecentsWindowFlags.getEnableOverviewInWindow();
+        return useHomeIntentForWindow ? getHomeIntent() : mGestureState.getOverviewIntent();
     }
     /**
      * Called when the value of {@link #mCurrentShift} changes
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 914855b..4280baf 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -82,6 +82,7 @@
                             taskKey.numActivities,
                             taskKey.isTopActivityNoDisplay,
                             taskKey.isActivityStackTransparent,
+                            taskKey.userId,
                         ) -> null
 
                         !taskContainer.task.isDockable -> null
diff --git a/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt b/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt
index f97cf9c..3b823f5 100644
--- a/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt
@@ -80,6 +80,7 @@
                             taskKey.numActivities,
                             taskKey.isTopActivityNoDisplay,
                             taskKey.isActivityStackTransparent,
+                            taskKey.userId,
                         ) -> null
 
                         else -> {
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 081ed9d..e5cbc66 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -63,13 +63,25 @@
             "TYPE_BUBBLE_BAR",              // 16
     };
 
-    InputConsumer NO_OP = () -> TYPE_NO_OP;
+    InputConsumer DEFAULT_NO_OP = createNoOpInputConsumer(Display.DEFAULT_DISPLAY);
+
+    static InputConsumer createNoOpInputConsumer(int displayId) {
+        return new InputConsumer() {
+            @Override
+            public int getType() {
+                return TYPE_NO_OP;
+            }
+
+            @Override
+            public int getDisplayId() {
+                return displayId;
+            }
+        };
+    }
 
     int getType();
 
-    default int getDisplayId() {
-        return Display.DEFAULT_DISPLAY;
-    }
+    int getDisplayId();
 
     /**
      * Returns true if the user has crossed the threshold for it to be an explicit action.
diff --git a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
index cd3ac12..c8ca534 100644
--- a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
+++ b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
@@ -57,7 +57,7 @@
     @JvmStatic
     fun <S : BaseState<S>, T> newConsumer(
         context: Context,
-        resetGestureInputConsumer: ResetGestureInputConsumer?,
+        userUnlocked: Boolean,
         overviewComponentObserver: OverviewComponentObserver,
         deviceState: RecentsAnimationDeviceState,
         previousGestureState: GestureState,
@@ -122,7 +122,8 @@
                     // camera).
                     createDeviceLockedInputConsumer(
                         context,
-                        resetGestureInputConsumer,
+                        userUnlocked,
+                        taskbarManager,
                         deviceState,
                         gestureState,
                         taskAnimationManager,
@@ -131,7 +132,10 @@
                     )
                 } else {
                     getDefaultInputConsumer(
-                        resetGestureInputConsumer,
+                        gestureState.displayId,
+                        userUnlocked,
+                        taskAnimationManager,
+                        taskbarManager,
                         reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX),
                     )
                 }
@@ -153,7 +157,8 @@
             base =
                 newBaseConsumer<S, T>(
                     context,
-                    resetGestureInputConsumer,
+                    userUnlocked,
+                    taskbarManager,
                     overviewComponentObserver,
                     deviceState,
                     previousGestureState,
@@ -172,7 +177,14 @@
                     "cannot start system gesture and recents " +
                         "animation was not running, trying to use default input consumer"
                 )
-            base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+            base =
+                getDefaultInputConsumer(
+                    gestureState.displayId,
+                    userUnlocked,
+                    taskAnimationManager,
+                    taskbarManager,
+                    reasonString,
+                )
         }
         if (deviceState.isGesturalNavMode || gestureState.isTrackpadGesture) {
             handleOrientationSetup(base)
@@ -237,7 +249,14 @@
                                 SUBSTRING_PREFIX,
                             )
                     // Bubbles can handle home gesture itself.
-                    base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+                    base =
+                        getDefaultInputConsumer(
+                            gestureState.displayId,
+                            userUnlocked,
+                            taskAnimationManager,
+                            taskbarManager,
+                            reasonString,
+                        )
                 }
             }
 
@@ -279,7 +298,14 @@
                                 SUBSTRING_PREFIX,
                             )
                     // Bubbles can handle home gesture itself.
-                    base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+                    base =
+                        getDefaultInputConsumer(
+                            gestureState.displayId,
+                            userUnlocked,
+                            taskAnimationManager,
+                            taskbarManager,
+                            reasonString,
+                        )
                 }
             }
 
@@ -374,7 +400,14 @@
                             "%sscreen pinning is active, trying to use default input consumer",
                             SUBSTRING_PREFIX,
                         )
-                base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+                base =
+                    getDefaultInputConsumer(
+                        gestureState.displayId,
+                        userUnlocked,
+                        taskAnimationManager,
+                        taskbarManager,
+                        reasonString,
+                    )
             }
 
             if (deviceState.canTriggerOneHandedAction(event)) {
@@ -411,7 +444,7 @@
             context,
             deviceState,
             inputMonitorCompat,
-            InputConsumer.NO_OP,
+            InputConsumer.createNoOpInputConsumer(gestureState.displayId),
             gestureState,
             motionEvent,
             CompoundString.NO_OP,
@@ -450,7 +483,8 @@
     @JvmStatic
     fun <S : BaseState<S>, T> newBaseConsumer(
         context: Context,
-        resetGestureInputConsumer: ResetGestureInputConsumer?,
+        userUnlocked: Boolean,
+        taskbarManager: TaskbarManager,
         overviewComponentObserver: OverviewComponentObserver,
         deviceState: RecentsAnimationDeviceState,
         previousGestureState: GestureState,
@@ -467,7 +501,8 @@
             // This handles apps showing over the lockscreen (e.g. camera)
             return createDeviceLockedInputConsumer(
                 context,
-                resetGestureInputConsumer,
+                userUnlocked,
+                taskbarManager,
                 deviceState,
                 gestureState,
                 taskAnimationManager,
@@ -521,7 +556,9 @@
 
         return if (gestureState.getContainerInterface<S, T>().isInLiveTileMode()) {
             createOverviewInputConsumer<S, T>(
-                resetGestureInputConsumer,
+                userUnlocked,
+                taskAnimationManager,
+                taskbarManager,
                 deviceState,
                 inputMonitorCompat,
                 previousGestureState,
@@ -534,7 +571,10 @@
             )
         } else if (runningTask == null) {
             getDefaultInputConsumer(
-                resetGestureInputConsumer,
+                gestureState.displayId,
+                userUnlocked,
+                taskAnimationManager,
+                taskbarManager,
                 reasonString.append("%srunning task == null", SUBSTRING_PREFIX),
             )
         } else if (
@@ -543,7 +583,9 @@
                 forceOverviewInputConsumer
         ) {
             createOverviewInputConsumer<S, T>(
-                resetGestureInputConsumer,
+                userUnlocked,
+                taskAnimationManager,
+                taskbarManager,
                 deviceState,
                 inputMonitorCompat,
                 previousGestureState,
@@ -565,7 +607,10 @@
             )
         } else if (deviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
             getDefaultInputConsumer(
-                resetGestureInputConsumer,
+                gestureState.displayId,
+                userUnlocked,
+                taskAnimationManager,
+                taskbarManager,
                 reasonString.append(
                     if (launcherChildActivityResumed)
                         "%sis launcher child-task, trying to use default input consumer"
@@ -592,7 +637,8 @@
 
     private fun createDeviceLockedInputConsumer(
         context: Context,
-        resetGestureInputConsumer: ResetGestureInputConsumer?,
+        userUnlocked: Boolean,
+        taskbarManager: TaskbarManager,
         deviceState: RecentsAnimationDeviceState,
         gestureState: GestureState,
         taskAnimationManager: TaskAnimationManager,
@@ -617,7 +663,10 @@
             )
         } else {
             getDefaultInputConsumer(
-                resetGestureInputConsumer,
+                gestureState.displayId,
+                userUnlocked,
+                taskAnimationManager,
+                taskbarManager,
                 reasonString.append(
                     if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture)
                         "%srunning task == null, trying to use default input consumer"
@@ -631,7 +680,9 @@
     }
 
     private fun <S : BaseState<S>, T> createOverviewInputConsumer(
-        resetGestureInputConsumer: ResetGestureInputConsumer?,
+        userUnlocked: Boolean,
+        taskAnimationManager: TaskAnimationManager,
+        taskbarManager: TaskbarManager,
         deviceState: RecentsAnimationDeviceState,
         inputMonitorCompat: InputMonitorCompat,
         previousGestureState: GestureState,
@@ -642,7 +693,10 @@
         val container: T =
             gestureState.getContainerInterface<S, T>().getCreatedContainer()
                 ?: return getDefaultInputConsumer(
-                    resetGestureInputConsumer,
+                    gestureState.displayId,
+                    userUnlocked,
+                    taskAnimationManager,
+                    taskbarManager,
                     reasonString.append(
                         "%sactivity == null, trying to use default input consumer",
                         SUBSTRING_PREFIX,
@@ -694,24 +748,34 @@
     }
 
     /** Returns the [ResetGestureInputConsumer] if user is unlocked, else NO_OP. */
-    private fun getDefaultInputConsumer(
-        resetGestureInputConsumer: ResetGestureInputConsumer?,
+    @JvmStatic
+    fun getDefaultInputConsumer(
+        displayId: Int,
+        userUnlocked: Boolean,
+        taskAnimationManager: TaskAnimationManager?,
+        taskbarManager: TaskbarManager?,
         reasonString: CompoundString,
     ): InputConsumer {
-        return if (resetGestureInputConsumer != null) {
+        return if (userUnlocked && taskAnimationManager != null && taskbarManager != null) {
             reasonString.append(
-                "%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer",
+                "%sResetGestureInputConsumer available, using ResetGestureInputConsumer",
                 SUBSTRING_PREFIX,
             )
-            resetGestureInputConsumer
+            ResetGestureInputConsumer(displayId, taskAnimationManager) {
+                taskbarManager.getTaskbarForDisplay(displayId)
+            }
         } else {
             reasonString.append(
-                "%smResetGestureInputConsumer not initialized, using no-op input consumer",
+                "%s${
+                    if (userUnlocked) "user is locked"
+                    else if (taskAnimationManager == null) "taskAnimationManager is null"
+                    else "taskbarManager is null"
+                }, using no-op input consumer",
                 SUBSTRING_PREFIX,
             )
-            // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
+            // ResetGestureInputConsumer isn't available until onUserUnlocked(), so reset to
             // NO_OP until then (we never want these to be null).
-            InputConsumer.NO_OP
+            InputConsumer.createNoOpInputConsumer(displayId)
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 2ff42cd..783ec2c 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -220,7 +220,7 @@
             mHandler.post(() -> {
                 LauncherBackAnimationController controller = mControllerRef.get();
                 if (controller != null) {
-                    controller.initBackMotion(backEvent);
+                    controller.startBack(backEvent);
                     mProgressAnimator.onBackStarted(backEvent, event -> {
                         float backProgress = event.getProgress();
                         controller.mBackProgress =
@@ -270,7 +270,6 @@
                 }
             }
             controller.mAnimationFinishedCallback = finishedCallback;
-            controller.startBack();
         }
 
         @Override
@@ -295,32 +294,34 @@
         mBackCallback = null;
     }
 
-    private void initBackMotion(BackMotionEvent backEvent) {
+    private void startBack(BackMotionEvent backEvent) {
         // in case we're still animating an onBackCancelled event, let's remove the finish-
         // callback from the progress animator to prevent calling finishAnimation() before
         // restarting a new animation
-        // Side note: initBackMotion is never called during the post-commit phase if the back
-        // gesture was committed (not cancelled). BackAnimationController prevents that. Therefore
-        // we don't have to handle that case.
+        // Side note: startBack is never called during the post-commit phase if the back gesture
+        // was committed (not cancelled). BackAnimationController prevents that. Therefore we
+        // don't have to handle that case.
         mProgressAnimator.removeOnBackCancelledFinishCallback();
 
         mBackInProgress = true;
-        mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
-    }
-    private void startBack() {
-        if (mBackTarget == null) {
+        RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget();
+
+        if (appTarget == null || appTarget.leash == null || !appTarget.leash.isValid()) {
             return;
         }
 
         mTransaction
-                .show(mBackTarget.leash)
+                .show(appTarget.leash)
                 .setAnimationTransaction();
-        mStartRect.set(mBackTarget.windowConfiguration.getMaxBounds());
+        mBackTarget = appTarget;
+        mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
+
+        mStartRect.set(appTarget.windowConfiguration.getMaxBounds());
 
         // inset bottom in case of taskbar being present
         if (!predictiveBackThreeButtonNav() || mLauncher.getDeviceProfile().isTaskbarPresent
                 || DisplayController.getNavigationMode(mLauncher) == NavigationMode.NO_BUTTON) {
-            mStartRect.inset(0, 0, 0, mBackTarget.contentInsets.bottom);
+            mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom);
         }
 
         mLauncherTargetView = mQuickstepTransitionManager.findLauncherView(
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index bf87291..152630a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -28,6 +28,7 @@
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.traceSection
 import com.android.internal.jank.Cuj
 import com.android.launcher3.Flags.enableAltTabKqsOnConnectedDisplays
 import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
@@ -74,7 +75,6 @@
 constructor(
     private val touchInteractionService: TouchInteractionService,
     private val overviewComponentObserver: OverviewComponentObserver,
-    private val taskAnimationManager: TaskAnimationManager,
     private val dispatcherProvider: DispatcherProvider = ProductionDispatchers,
     private val recentsDisplayModel: RecentsDisplayModel,
     private val focusState: FocusState,
@@ -143,35 +143,38 @@
      * completion (returns false).
      */
     @UiThread
-    private fun processNextCommand() {
-        val command: CommandInfo =
-            commandQueue.firstOrNull()
-                ?: run {
-                    Log.d(TAG, "no pending commands to be executed.")
-                    return
-                }
-
-        command.status = CommandStatus.PROCESSING
-        Log.d(TAG, "executing command: $command")
-
-        if (enableOverviewCommandHelperTimeout()) {
-            coroutineScope.launch(dispatcherProvider.main) {
-                withTimeout(QUEUE_WAIT_DURATION_IN_MS) {
-                    executeCommandSuspended(command)
-                    ensureActive()
-                    onCommandFinished(command)
-                }
+    private fun processNextCommand() =
+        traceSection("OverviewCommandHelper.processNextCommand") {
+            val command: CommandInfo? = commandQueue.firstOrNull()
+            if (command == null) {
+                Log.d(TAG, "no pending commands to be executed.")
+                return@traceSection
             }
-        } else {
-            val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) })
-            Log.d(TAG, "command executed: $command with result: $result")
-            if (result) {
-                onCommandFinished(command)
+
+            command.status = CommandStatus.PROCESSING
+            Log.d(TAG, "executing command: $command")
+
+            if (enableOverviewCommandHelperTimeout()) {
+                coroutineScope.launch(dispatcherProvider.main) {
+                    traceSection("OverviewCommandHelper.executeCommandWithTimeout") {
+                        withTimeout(QUEUE_WAIT_DURATION_IN_MS) {
+                            executeCommandSuspended(command)
+                            ensureActive()
+                            onCommandFinished(command)
+                        }
+                    }
+                }
             } else {
-                Log.d(TAG, "waiting for command callback: $command")
+                val result =
+                    executeCommand(command, onCallbackResult = { onCommandFinished(command) })
+                Log.d(TAG, "command executed: $command with result: $result")
+                if (result) {
+                    onCommandFinished(command)
+                } else {
+                    Log.d(TAG, "waiting for command callback: $command")
+                }
             }
         }
-    }
 
     /**
      * Executes the task and returns true if next task can be executed. If false, then the next task
@@ -453,6 +456,14 @@
                 }
             }
 
+        val displayId = gestureState.displayId
+        val taskAnimationManager =
+            recentsDisplayModel.getTaskAnimationManager(displayId)
+                ?: run {
+                    Log.e(TAG, "No TaskAnimationManager found for display $displayId")
+                    ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable(displayId)
+                    return false
+                }
         if (taskAnimationManager.isRecentsAnimationRunning) {
             command.setAnimationCallbacks(
                 taskAnimationManager.continueRecentsAnimation(gestureState)
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index cc5b2da..dab78c5 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -511,13 +511,14 @@
             // When the multiple desktop feature is disabled, there can only be up to a single desk
             // on each display, The desk ID doesn't matter and should not be used.
             return MapsKt.map(perDisplayTasks,
-                    it -> new DesktopTask(DesktopVisibilityController.INACTIVE_DESK_ID,
+                    it -> new DesktopTask(DesktopVisibilityController.INACTIVE_DESK_ID, it.getKey(),
                             it.getValue()));
         } else {
             final int deskId = recentTaskInfo.getDeskId();
+            final int displayId = recentTaskInfo.getDeskDisplayId();
             List<Task> tasks = CollectionsKt.map(recentTaskInfo.getTaskInfoList(),
                     it -> createTask(it, minimizedTaskIds));
-            return List.of(new DesktopTask(deskId, tasks));
+            return List.of(new DesktopTask(deskId, displayId, tasks));
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
index 506f85d..cd87d93 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -690,10 +690,10 @@
             bubbles?.showDropTarget(show, bubbleBarLocation)
         }
 
-    /** Tells SysUI to move the bubble to full screen. */
-    fun moveBubbleToFullscreen(key: String) {
-        executeWithErrorLog({ "Failed to call moveBubbleToFullscreen"}) {
-            bubbles?.moveBubbleToFullscreen(key)
+    /** Tells SysUI to move the dragged bubble to full screen. */
+    fun moveDraggedBubbleToFullscreen(key: String, dropLocation: Point) {
+        executeWithErrorLog({ "Failed to call moveDraggedBubbleToFullscreen"}) {
+            bubbles?.moveDraggedBubbleToFullscreen(key, dropLocation)
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 1c7f23c..4f00381 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -77,6 +77,7 @@
 
     private boolean mRecentsAnimationStartPending = false;
     private boolean mShouldIgnoreMotionEvents = false;
+    private final int mDisplayId;
 
     private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
         @Override
@@ -101,10 +102,13 @@
         }
     };
 
-    TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState) {
+    public TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState,
+            int displayId) {
         mCtx = ctx;
         mDeviceState = deviceState;
+        mDisplayId = displayId;
     }
+
     SystemUiProxy getSystemUiProxy() {
         return SystemUiProxy.INSTANCE.get(mCtx);
     }
@@ -489,6 +493,7 @@
 
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "TaskAnimationManager:");
+        pw.println(prefix + "\tmDisplayId=" + mDisplayId);
 
         if (enableHandleDelayedGestureCallbacks()) {
             pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 855ff98..d161d45 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -433,9 +433,7 @@
         out.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
-                for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
-                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
-                }
+                recentsView.setDrawBelowRecents(false, remoteTargetHandles);
             }
 
             @Override
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index b3d9da3..8116a88 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.util.SplitConfigurationOptions.StageType;
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.dagger.QuickstepBaseAppComponent;
+import com.android.quickstep.util.DesksUtils;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -341,7 +342,8 @@
 
             ArrayList<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
             // Strip the pinned task and recents task
-            tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
+            tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t)
+                    ||  DesksUtils.isDesktopWallpaperTask(t));
             return new CachedTaskInfo(tasks);
         }
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 741ae7d..6912ba7 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -35,6 +35,7 @@
 import static com.android.quickstep.GestureState.DEFAULT_STATE;
 import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType;
 import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER;
+import static com.android.quickstep.InputConsumer.createNoOpInputConsumer;
 import static com.android.quickstep.InputConsumerUtils.newConsumer;
 import static com.android.quickstep.InputConsumerUtils.tryCreateAssistantInputConsumer;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -98,7 +99,6 @@
 import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
 import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
-import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActiveGestureLog.CompoundString;
 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -557,12 +557,11 @@
     private OverviewComponentObserver mOverviewComponentObserver;
     private InputConsumerController mInputConsumer;
     private RecentsAnimationDeviceState mDeviceState;
-    private TaskAnimationManager mTaskAnimationManager;
 
-    private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
-    private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP;
+    private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.DEFAULT_NO_OP;
+    private @NonNull InputConsumer mConsumer = InputConsumer.DEFAULT_NO_OP;
     private Choreographer mMainChoreographer;
-    private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer;
+    private boolean mUserUnlocked = false;
     private GestureState mGestureState = DEFAULT_STATE;
 
     private InputMonitorDisplayModel mInputMonitorDisplayModel;
@@ -667,7 +666,7 @@
         if (ENABLE_GESTURE_NAV_ON_CONNECTED_DISPLAYS.isTrue()) {
             mInputMonitorDisplayModel = new InputMonitorDisplayModel(this);
         } else {
-            mInputMonitorCompat = new InputMonitorCompat("swipe-up", Display.DEFAULT_DISPLAY);
+            mInputMonitorCompat = new InputMonitorCompat("swipe-up", DEFAULT_DISPLAY);
             mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
                     mMainChoreographer, this::onInputEvent);
         }
@@ -687,13 +686,11 @@
     public void onUserUnlocked() {
         Log.d(TAG, "onUserUnlocked: userId=" + getUserId()
                 + " instance=" + System.identityHashCode(this));
-        mTaskAnimationManager = new TaskAnimationManager(this, mDeviceState);
         mOverviewComponentObserver = OverviewComponentObserver.INSTANCE.get(this);
         mOverviewCommandHelper = new OverviewCommandHelper(this,
-                mOverviewComponentObserver, mTaskAnimationManager, mRecentsDisplayModel,
+                mOverviewComponentObserver, mRecentsDisplayModel,
                 SystemUiProxy.INSTANCE.get(this).getFocusState(), mTaskbarManager);
-        mResetGestureInputConsumer = new ResetGestureInputConsumer(
-                mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
+        mUserUnlocked = true;
         mInputConsumer.registerInputConsumer();
         for (int displayId : mDeviceState.getDisplaysWithSysUIState()) {
             onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags(displayId), displayId);
@@ -766,14 +763,18 @@
         if (LockedUserState.get(this).isUserUnlocked()) {
             long systemUiStateFlags = mDeviceState.getSystemUiStateFlags(displayId);
             mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags, displayId);
-            if (displayId == Display.DEFAULT_DISPLAY) {
+            if (displayId == DEFAULT_DISPLAY) {
                 // The following don't care about non-default displays, at least for now. If they
                 // ever will, they should be taken care of.
                 SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
                 mOverviewComponentObserver.setHomeDisabled(mDeviceState.isHomeDisabled());
                 // TODO b/399371607 - Propagate to taskAnimationManager once overview is multi
                 //  display.
-                mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags);
+                TaskAnimationManager taskAnimationManager =
+                        mRecentsDisplayModel.getTaskAnimationManager(displayId);
+                if (taskAnimationManager != null) {
+                    taskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags);
+                }
             }
         }
     }
@@ -865,11 +866,18 @@
         boolean isHoverActionWithoutConsumer = enableCursorHoverStates()
                 && isHoverActionWithoutConsumer(event);
 
+        TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager(
+                displayId);
+        if (taskAnimationManager == null) {
+            Log.e(TAG, "TaskAnimationManager not available for displayId " + displayId);
+            ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable(displayId);
+            return;
+        }
         if (enableHandleDelayedGestureCallbacks()) {
             if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
-                mTaskAnimationManager.notifyNewGestureStart();
+                taskAnimationManager.notifyNewGestureStart();
             }
-            if (mTaskAnimationManager.shouldIgnoreMotionEvents()) {
+            if (taskAnimationManager.shouldIgnoreMotionEvents()) {
                 if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
                     ActiveGestureProtoLogProxy.logOnInputIgnoringFollowingEvents(displayId);
                 }
@@ -917,7 +925,7 @@
                 } else {
                     reasonString.append(" but event cannot trigger Assistant, "
                             + "consuming gesture as no-op");
-                    mUncheckedConsumer = InputConsumer.NO_OP;
+                    mUncheckedConsumer = createNoOpInputConsumer(displayId);
                 }
             } else if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
                     || isHoverActionWithoutConsumer || isOnBubbles) {
@@ -934,12 +942,12 @@
                 mGestureState = newGestureState;
                 mConsumer = newConsumer(
                         this,
-                        mResetGestureInputConsumer,
+                        mUserUnlocked,
                         mOverviewComponentObserver,
                         mDeviceState,
                         prevGestureState,
                         mGestureState,
-                        mTaskAnimationManager,
+                        taskAnimationManager,
                         inputMonitorCompat,
                         getSwipeUpHandlerFactory(),
                         this::onConsumerInactive,
@@ -968,19 +976,22 @@
                         + "consuming gesture for one-handed action");
                 // Consume gesture event for triggering one handed feature.
                 mUncheckedConsumer = new OneHandedModeInputConsumer(
-                        this, displayId, mDeviceState, InputConsumer.NO_OP, inputMonitorCompat);
+                        this,
+                        displayId,
+                        mDeviceState,
+                        InputConsumer.createNoOpInputConsumer(displayId), inputMonitorCompat);
             } else {
-                mUncheckedConsumer = InputConsumer.NO_OP;
+                mUncheckedConsumer = InputConsumer.createNoOpInputConsumer(displayId);
             }
         } else {
             // Other events
-            if (mUncheckedConsumer != InputConsumer.NO_OP) {
+            if (mUncheckedConsumer.getType() != InputConsumer.TYPE_NO_OP) {
                 // Only transform the event if we are handling it in a proper consumer
                 mRotationTouchHelper.setOrientationTransformIfNeeded(event);
             }
         }
 
-        if (mUncheckedConsumer != InputConsumer.NO_OP) {
+        if (mUncheckedConsumer.getType() != InputConsumer.TYPE_NO_OP) {
             switch (action) {
                 case ACTION_DOWN:
                     ActiveGestureProtoLogProxy.logOnInputEventActionDown(displayId, reasonString);
@@ -1053,7 +1064,9 @@
             GestureState.TrackpadGestureType trackpadGestureType) {
         final GestureState gestureState;
         TopTaskTracker.CachedTaskInfo taskInfo;
-        if (mTaskAnimationManager.isRecentsAnimationRunning()) {
+        TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager(
+                displayId);
+        if (taskAnimationManager != null && taskAnimationManager.isRecentsAnimationRunning()) {
             gestureState = new GestureState(
                     mOverviewComponentObserver, displayId, ActiveGestureLog.INSTANCE.getLogId());
             TopTaskTracker.CachedTaskInfo previousTaskInfo = previousGestureState.getRunningTask();
@@ -1100,7 +1113,12 @@
     }
 
     private void reset(int displayId) {
-        mConsumer = mUncheckedConsumer = getDefaultInputConsumer();
+        mConsumer = mUncheckedConsumer = InputConsumerUtils.getDefaultInputConsumer(
+                displayId,
+                mUserUnlocked,
+                mRecentsDisplayModel.getTaskAnimationManager(displayId),
+                mTaskbarManager,
+                CompoundString.NO_OP);
         mGestureState = DEFAULT_STATE;
         // By default, use batching of the input events, but check receiver before using in the rare
         // case that the monitor was disposed before the swipe settled
@@ -1110,29 +1128,6 @@
         }
     }
 
-    private @NonNull InputConsumer getDefaultInputConsumer() {
-        return getDefaultInputConsumer(CompoundString.NO_OP);
-    }
-
-    /**
-     * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP.
-     */
-    private @NonNull InputConsumer getDefaultInputConsumer(@NonNull CompoundString reasonString) {
-        if (mResetGestureInputConsumer != null) {
-            reasonString.append(
-                    "%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer",
-                    SUBSTRING_PREFIX);
-            return mResetGestureInputConsumer;
-        } else {
-            reasonString.append(
-                    "%smResetGestureInputConsumer not initialized, using no-op input consumer",
-                    SUBSTRING_PREFIX);
-            // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
-            // NO_OP until then (we never want these to be null).
-            return InputConsumer.NO_OP;
-        }
-    }
-
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         if (!LockedUserState.get(this).isUserUnlocked()) {
@@ -1208,13 +1203,11 @@
             if (createdOverviewContainer != null) {
                 createdOverviewContainer.getDeviceProfile().dump(this, "", pw);
             }
+            resource.getTaskAnimationManager().dump("\t", pw);
         }
         pw.println("\tmConsumer=" + mConsumer.getName());
         ActiveGestureLog.INSTANCE.dump("", pw);
         RecentsModel.INSTANCE.get(this).dump("", pw);
-        if (mTaskAnimationManager != null) {
-            mTaskAnimationManager.dump("", pw);
-        }
         mTaskbarManager.dumpLogs("", pw);
         DesktopVisibilityController.INSTANCE.get(this).dumpLogs("", pw);
         pw.println("ContextualSearchStateManager:");
@@ -1226,22 +1219,28 @@
 
     private AbsSwipeUpHandler createLauncherSwipeHandler(
             GestureState gestureState, long touchTimeMs) {
-        return new LauncherSwipeHandlerV2(this, mTaskAnimationManager,
-                gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
+        TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager(
+                gestureState.getDisplayId());
+        return new LauncherSwipeHandlerV2(this, taskAnimationManager,
+                gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(),
                 mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this));
     }
 
     private AbsSwipeUpHandler createFallbackSwipeHandler(
             GestureState gestureState, long touchTimeMs) {
-        return new FallbackSwipeHandler(this, mTaskAnimationManager,
-                gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
+        TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager(
+                gestureState.getDisplayId());
+        return new FallbackSwipeHandler(this, taskAnimationManager,
+                gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(),
                 mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this));
     }
 
     private AbsSwipeUpHandler createRecentsWindowSwipeHandler(
             GestureState gestureState, long touchTimeMs) {
-        return new RecentsWindowSwipeHandler(this, mTaskAnimationManager,
-                gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
+        TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager(
+                gestureState.getDisplayId());
+        return new RecentsWindowSwipeHandler(this, taskAnimationManager,
+                gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(),
                 mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this));
     }
 
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 8ec97ed..29b6626 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -292,8 +292,7 @@
 
         // disabling this so app icons aren't drawn on top of recent tasks.
         if (isOverlayEnabled && !RecentsWindowFlags.Companion.getEnableOverviewInWindow()) {
-            runActionOnRemoteHandles(remoteTargetHandle ->
-                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
+            mBlurUtils.setDrawLiveTileBelowRecents(true);
         }
     }
 
@@ -303,6 +302,7 @@
         if (enabled) {
             RecentsState state = mContainer.getStateManager().getState();
             setDisallowScrollToClearAll(!state.hasClearAllButton());
+            setDisallowScrollToAddDesk(!state.hasAddDeskButton());
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
index 12dc177..0f611eb 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
 import androidx.core.util.valueIterator
 import com.android.launcher3.dagger.ApplicationContext
 import com.android.launcher3.dagger.LauncherAppSingleton
@@ -26,6 +27,8 @@
 import com.android.launcher3.util.WallpaperColorHints
 import com.android.quickstep.DisplayModel
 import com.android.quickstep.FallbackWindowInterface
+import com.android.quickstep.RecentsAnimationDeviceState
+import com.android.quickstep.TaskAnimationManager
 import com.android.quickstep.dagger.QuickstepBaseAppComponent
 import com.android.quickstep.fallback.window.RecentsDisplayModel.RecentsDisplayResource
 import com.android.quickstep.fallback.window.RecentsWindowFlags.Companion.enableOverviewInWindow
@@ -55,8 +58,11 @@
     init {
         if (enableOverviewInWindow) {
             registerDisplayListener()
-            tracker.addCloseable { destroy() }
+        } else {
+            // Always create resource for default display
+            storeDisplayResource(DEFAULT_DISPLAY)
         }
+        tracker.addCloseable { destroy() }
     }
 
     override fun createDisplayResource(display: Display): RecentsDisplayResource {
@@ -75,6 +81,10 @@
         return getDisplayResource(displayId)?.fallbackWindowInterface
     }
 
+    fun getTaskAnimationManager(displayId: Int): TaskAnimationManager? {
+        return getDisplayResource(displayId)?.taskAnimationManager
+    }
+
     val activeDisplayResources: Iterable<RecentsDisplayResource>
         get() =
             object : Iterable<RecentsDisplayResource> {
@@ -86,12 +96,20 @@
         val displayContext: Context,
         val wallpaperColorHints: Int,
     ) : DisplayResource() {
-        val recentsWindowManager = RecentsWindowManager(displayContext, wallpaperColorHints)
-        val fallbackWindowInterface: FallbackWindowInterface =
-            FallbackWindowInterface(recentsWindowManager)
+        val recentsWindowManager =
+            if (enableOverviewInWindow) RecentsWindowManager(displayContext, wallpaperColorHints)
+            else null
+        val fallbackWindowInterface =
+            if (enableOverviewInWindow) FallbackWindowInterface(recentsWindowManager) else null
+        val taskAnimationManager =
+            TaskAnimationManager(
+                displayContext,
+                RecentsAnimationDeviceState.INSTANCE.get(displayContext),
+                displayId,
+            )
 
         override fun cleanup() {
-            recentsWindowManager.destroy()
+            recentsWindowManager?.destroy()
         }
 
         override fun dump(prefix: String, writer: PrintWriter) {
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt
index 9953154..d880774 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt
@@ -29,8 +29,15 @@
         val enableFallbackOverviewInWindow: DesktopModeFlag =
             DesktopModeFlag(Flags::enableFallbackOverviewInWindow, false)
 
+        @JvmField
+        val enableOverviewOnConnectedDisplays: DesktopModeFlag =
+            DesktopModeFlag(Flags::enableOverviewOnConnectedDisplays, false)
+
         @JvmStatic
         val enableOverviewInWindow
-            get() = enableLauncherOverviewInWindow.isTrue || enableFallbackOverviewInWindow.isTrue
+            get() =
+                enableLauncherOverviewInWindow.isTrue ||
+                    enableFallbackOverviewInWindow.isTrue ||
+                    enableOverviewOnConnectedDisplays.isTrue
     }
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index c8cf58c..2db7573 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -58,7 +58,6 @@
 import com.android.quickstep.RecentsAnimationTargets;
 import com.android.quickstep.RotationTouchHelper;
 import com.android.quickstep.TaskAnimationManager;
-import com.android.quickstep.fallback.window.RecentsWindowFlags;
 import com.android.quickstep.util.CachedEventDispatcher;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.NavBarPosition;
@@ -437,9 +436,7 @@
             mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
             notifyGestureStarted(true /*isLikelyToStartNewTask*/);
         } else {
-            // todo differentiate intent based on if we are on home or in app for overview in window
-            Intent intent = new Intent(RecentsWindowFlags.Companion.getEnableOverviewInWindow()
-                    ? mInteractionHandler.getHomeIntent() : mInteractionHandler.getLaunchIntent());
+            Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
             intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
             mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
                     mInteractionHandler);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
deleted file mode 100644
index 349f4d2..0000000
--- a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.inputconsumers;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.quickstep.InputConsumer;
-import com.android.quickstep.TaskAnimationManager;
-
-import java.util.function.Supplier;
-
-/**
- * A NO_OP input consumer which also resets any pending gesture
- */
-public class ResetGestureInputConsumer implements InputConsumer {
-
-    private final TaskAnimationManager mTaskAnimationManager;
-    private final Supplier<TaskbarActivityContext> mActivityContextSupplier;
-
-    public ResetGestureInputConsumer(
-            TaskAnimationManager taskAnimationManager,
-            Supplier<TaskbarActivityContext> activityContextSupplier) {
-        mTaskAnimationManager = taskAnimationManager;
-        mActivityContextSupplier = activityContextSupplier;
-    }
-
-    @Override
-    public int getType() {
-        return TYPE_RESET_GESTURE;
-    }
-
-    @Override
-    public void onMotionEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN
-                && mTaskAnimationManager.isRecentsAnimationRunning()) {
-            TaskbarActivityContext tac = mActivityContextSupplier.get();
-            mTaskAnimationManager.finishRunningRecentsAnimation(
-                    /* toHome= */ tac != null && !tac.isInApp());
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt
new file mode 100644
index 0000000..96e7943
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.inputconsumers
+
+import android.view.MotionEvent
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.quickstep.InputConsumer
+import com.android.quickstep.TaskAnimationManager
+import java.util.function.Supplier
+
+/** A NO_OP input consumer which also resets any pending gesture */
+class ResetGestureInputConsumer(
+    private val displayId: Int,
+    private val taskAnimationManager: TaskAnimationManager,
+    private val activityContextSupplier: Supplier<TaskbarActivityContext?>,
+) : InputConsumer {
+    override fun getType() = InputConsumer.TYPE_RESET_GESTURE
+
+    override fun getDisplayId() = displayId
+
+    override fun onMotionEvent(ev: MotionEvent) {
+        if (
+            ev.action == MotionEvent.ACTION_DOWN && taskAnimationManager.isRecentsAnimationRunning
+        ) {
+            val tac = activityContextSupplier.get()
+            taskAnimationManager.finishRunningRecentsAnimation(
+                /* toHome= */ tac != null && !tac.isInApp
+            )
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index c4e343e..b8f43a4 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -661,7 +661,7 @@
     ): SplitIconPositions {
         return if (Flags.enableOverviewIconMenu()) {
             if (isRtl) {
-                SplitIconPositions(0, -(totalThumbnailHeight - primarySnapshotHeight))
+                SplitIconPositions(-(totalThumbnailHeight - primarySnapshotHeight), 0)
             } else {
                 SplitIconPositions(0, primarySnapshotHeight + dividerSize)
             }
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index 67358bbb..80b50cb 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -248,14 +248,14 @@
         val iconCenter = iconAppChipView.getHeight() / 2f
 
         if (isRtl) {
-            iconMenuParams.gravity = Gravity.TOP or Gravity.END
+            iconMenuParams.gravity = Gravity.TOP or Gravity.START
             iconMenuParams.topMargin = iconMenuMargin
             iconMenuParams.marginEnd = thumbnailTopMargin
             // Use half menu height to place the pivot within the X/Y center of icon in the menu.
             iconAppChipView.pivotX = iconMenuParams.width / 2f
             iconAppChipView.pivotY = iconMenuParams.width / 2f
         } else {
-            iconMenuParams.gravity = Gravity.BOTTOM or Gravity.START
+            iconMenuParams.gravity = Gravity.BOTTOM or Gravity.END
             iconMenuParams.topMargin = 0
             iconMenuParams.marginEnd = 0
             iconAppChipView.pivotX = iconCenter
@@ -409,7 +409,7 @@
         if (Flags.enableOverviewIconMenu()) {
             val appChipView = iconView as IconAppChipView
             layoutParams.gravity =
-                if (isRtl) Gravity.TOP or Gravity.END else Gravity.BOTTOM or Gravity.START
+                if (isRtl) Gravity.TOP or Gravity.START else Gravity.BOTTOM or Gravity.END
             appChipView.layoutParams = layoutParams
             appChipView.setSplitTranslationX(0f)
             appChipView.setSplitTranslationY(translationY.toFloat())
diff --git a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt
index aa1c236..679daf8 100644
--- a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt
+++ b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt
@@ -17,6 +17,7 @@
 package com.android.quickstep.recents.ui.mapper
 
 import android.view.View.OnClickListener
+import com.android.launcher3.Flags.enableDesktopExplodedView
 import com.android.quickstep.recents.ui.viewmodel.TaskData
 import com.android.quickstep.task.thumbnail.TaskHeaderUiState
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState
@@ -99,7 +100,8 @@
         hasHeader: Boolean,
         clickCloseListener: OnClickListener?,
     ) =
-        hasHeader &&
+        enableDesktopExplodedView() &&
+            hasHeader &&
             taskData.icon != null &&
             taskData.titleDescription != null &&
             clickCloseListener != null
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt
index 2dbd811..a40929c 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt
@@ -26,7 +26,6 @@
 import android.view.ViewOutlineProvider
 import android.widget.LinearLayout
 import androidx.core.view.isInvisible
-import com.android.launcher3.Flags.enableDesktopExplodedView
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.R
 import com.android.launcher3.util.ViewPool
@@ -65,7 +64,6 @@
 
     override fun onFinishInflate() {
         super.onFinishInflate()
-        maybeCreateHeader()
         createTaskThumbnailView()
     }
 
@@ -122,12 +120,12 @@
         invalidateOutline()
     }
 
-    private fun maybeCreateHeader() {
-        if (enableDesktopExplodedView() && taskHeaderView == null) {
+    private fun createHeaderView(taskHeaderState: TaskHeaderUiState) {
+        if (taskHeaderView == null && taskHeaderState is TaskHeaderUiState.ShowHeader) {
             taskHeaderView =
                 LayoutInflater.from(context).inflate(R.layout.task_header_view, this, false)
                     as TaskHeaderView
-            addView(taskHeaderView)
+            addView(taskHeaderView, 0)
         }
     }
 
@@ -153,6 +151,7 @@
         taskThumbnailUiState: TaskThumbnailUiState,
         taskId: Int?,
     ) {
+        createHeaderView(taskHeaderState)
         taskHeaderView?.setState(taskHeaderState)
         taskThumbnailView?.setState(taskThumbnailUiState, taskId)
     }
diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
index 5d6bb1d..89f1e33 100644
--- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java
+++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur;
 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 
 import android.app.WallpaperManager;
@@ -24,6 +25,9 @@
 import android.view.AttachedSurfaceControl;
 import android.view.SurfaceControl;
 
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -74,11 +78,14 @@
 
     /**
      * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
+     *
      * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
      */
     private float mDepth;
 
-    protected SurfaceControl mSurface;
+    protected SurfaceControl mBaseSurface;
+
+    protected SurfaceControl mBaseSurfaceOverride;
 
     // Hints that there is potentially content behind Launcher and that we shouldn't optimize by
     // marking the launcher surface as opaque.  Only used in certain Launcher states.
@@ -99,15 +106,29 @@
 
     protected boolean mWaitingOnSurfaceValidity;
 
+    private SurfaceControl mBlurSurface = null;
+
     public BaseDepthController(Launcher activity) {
         mLauncher = activity;
-        mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius);
+        if (Flags.allAppsBlur()) {
+            mMaxBlurRadius = activity.getResources().getDimensionPixelSize(
+                    R.dimen.max_depth_blur_radius_enhanced);
+        } else {
+            mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius);
+        }
         mWallpaperManager = activity.getSystemService(WallpaperManager.class);
 
         MultiPropertyFactory<BaseDepthController> depthProperty =
                 new MultiPropertyFactory<>(this, DEPTH, DEPTH_INDEX_COUNT, Float::max);
         stateDepth = depthProperty.get(DEPTH_INDEX_STATE_TRANSITION);
         widgetDepth = depthProperty.get(DEPTH_INDEX_WIDGET);
+        if (enableOverviewBackgroundWallpaperBlur()) {
+            mBlurSurface = new SurfaceControl.Builder()
+                    .setName("Overview Blur")
+                    .setHidden(false)
+                    .build();
+        }
+
     }
 
     protected void setCrossWindowBlursEnabled(boolean isEnabled) {
@@ -145,11 +166,11 @@
         if (!BlurUtils.supportsBlursOnWindows()) {
             return;
         }
-        if (mSurface == null) {
+        if (mBaseSurface == null) {
             Log.d(TAG, "mSurface is null and mCurrentBlur is: " + mCurrentBlur);
             return;
         }
-        if (!mSurface.isValid()) {
+        if (!mBaseSurface.isValid()) {
             Log.d(TAG, "mSurface is not valid");
             mWaitingOnSurfaceValidity = true;
             onInvalidSurface();
@@ -168,10 +189,21 @@
         mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg || mPauseBlurs
                 ? 0 : (int) (blurAmount * mMaxBlurRadius);
 
-        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
-                .setBackgroundBlurRadius(mSurface, mCurrentBlur)
-                .setOpaque(mSurface, isSurfaceOpaque);
-
+        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+        if (enableOverviewBackgroundWallpaperBlur() && mBlurSurface != null) {
+            // Reparent to launcher for full screen blur.
+            transaction.setBackgroundBlurRadius(mBlurSurface, mCurrentBlur)
+                    .reparent(mBlurSurface, mBaseSurface);
+            // Set mBlurSurface to be 1 layer behind mBaseSurface or mBaseSurfaceOverride.
+            if (mBaseSurfaceOverride != null && mBaseSurfaceOverride.isValid()) {
+                transaction.setRelativeLayer(mBlurSurface, mBaseSurfaceOverride, -1);
+            } else {
+                transaction.setRelativeLayer(mBlurSurface, mBaseSurface, -1);
+            }
+        } else {
+            transaction.setBackgroundBlurRadius(mBaseSurface, mCurrentBlur);
+        }
+        transaction.setOpaque(mBaseSurface, isSurfaceOpaque);
         // Set early wake-up flags when we know we're executing an expensive operation, this way
         // SurfaceFlinger will adjust its internal offsets to avoid jank.
         boolean wantsEarlyWakeUp = depth > 0 && depth < 1;
@@ -203,13 +235,26 @@
     }
 
     /**
+     * Sets the lowest surface that should not be blurred.
+     * <p>
+     * Blur is applied to below {@link #mBaseSurfaceOverride}. When set to {@code null}, blur is
+     * applied
+     * to below {@link #mBaseSurface}.
+     * </p>
+     */
+    public void setBaseSurfaceOverride(@Nullable SurfaceControl baseSurfaceOverride) {
+        this.mBaseSurfaceOverride = baseSurfaceOverride;
+        applyDepthAndBlur();
+    }
+
+    /**
      * Sets the specified app target surface to apply the blur to.
      */
-    protected void setSurface(SurfaceControl surface) {
-        if (mSurface != surface || mWaitingOnSurfaceValidity) {
-            mSurface = surface;
+    protected void setBaseSurface(SurfaceControl baseSurface) {
+        if (mBaseSurface != baseSurface || mWaitingOnSurfaceValidity) {
+            mBaseSurface = baseSurface;
             Log.d(TAG, "setSurface:\n\tmWaitingOnSurfaceValidity: " + mWaitingOnSurfaceValidity
-                    + "\n\tmSurface: " + mSurface);
+                    + "\n\tmBaseSurface: " + mBaseSurface);
             applyDepthAndBlur();
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
index 7e51fcf..d1d47b9 100644
--- a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
@@ -114,6 +114,8 @@
          *
          * @param borderRadiusPx the radius of the border's corners, in pixels
          * @param borderWidthPx the width of the border, in pixels
+         * @param borderStrokePx the stroke width used to paint the border, in pixels. If smaller
+         *     than border width, it gets drawn at the outside edge of the border.
          * @param boundsBuilder callback to update the border bounds
          * @param targetView the view that will be drawing the border
          * @param contentView the view around which the border will be drawn. this view will be
@@ -128,6 +130,7 @@
         fun createScalingBorderAnimator(
             @Px borderRadiusPx: Int,
             @Px borderWidthPx: Int,
+            @Px borderStrokePx: Int,
             boundsBuilder: (rect: Rect?) -> Unit,
             targetView: View,
             contentView: View,
@@ -139,7 +142,13 @@
             return BorderAnimator(
                 borderRadiusPx,
                 borderColor,
-                ScalingParams(borderWidthPx, boundsBuilder, targetView, contentView),
+                ScalingParams(
+                    borderWidthPx,
+                    borderStrokePx,
+                    boundsBuilder,
+                    targetView,
+                    contentView,
+                ),
                 appearanceDurationMs,
                 disappearanceDurationMs,
                 interpolator,
@@ -151,7 +160,7 @@
         val interpolatedProgress = interpolator.getInterpolation(borderAnimationProgress.value)
         borderAnimationParams.animationProgress = interpolatedProgress
         borderPaint.alpha = (255 * interpolatedProgress).roundToInt()
-        borderPaint.strokeWidth = borderAnimationParams.borderWidth
+        borderPaint.strokeWidth = borderAnimationParams.borderStroke
         borderAnimationParams.targetView.invalidate()
     }
 
@@ -170,7 +179,7 @@
                 /* bottom= */ borderBounds.bottom - alignmentAdjustment,
                 /* rx= */ radius,
                 /* ry= */ radius,
-                /* paint= */ borderPaint
+                /* paint= */ borderPaint,
             )
         }
     }
@@ -212,6 +221,7 @@
     /** Params for handling different target view layout situations. */
     private abstract class BorderAnimationParams(
         @field:Px @param:Px val borderWidthPx: Int,
+        @field:Px @param:Px val borderStrokePx: Int,
         private val boundsBuilder: (rect: Rect) -> Unit,
         val targetView: View,
     ) {
@@ -222,12 +232,12 @@
         abstract val alignmentAdjustmentInset: Int
         abstract val radiusAdjustment: Float
 
-        val borderWidth: Float
-            get() = borderWidthPx * animationProgress
+        val borderStroke: Float
+            get() = borderStrokePx * animationProgress
 
         val alignmentAdjustment: Float
             // Outset the border by half the width to create an outwards-growth animation
-            get() = -borderWidth / 2f + alignmentAdjustmentInset
+            get() = -borderStroke / 2f + alignmentAdjustmentInset
 
         open fun onShowBorder() {
             if (layoutChangeListener == null) {
@@ -253,7 +263,7 @@
         @Px borderWidthPx: Int,
         boundsBuilder: (Rect) -> Unit,
         targetView: View,
-    ) : BorderAnimationParams(borderWidthPx, boundsBuilder, targetView) {
+    ) : BorderAnimationParams(borderWidthPx, borderWidthPx, boundsBuilder, targetView) {
         override val alignmentAdjustmentInset = 0
         override val radiusAdjustment: Float
             get() = -alignmentAdjustment
@@ -265,12 +275,13 @@
      */
     private class ScalingParams(
         @Px borderWidthPx: Int,
+        @Px borderStrokePx: Int,
         boundsBuilder: (rect: Rect?) -> Unit,
         targetView: View,
         private val contentView: View,
-    ) : BorderAnimationParams(borderWidthPx, boundsBuilder, targetView) {
+    ) : BorderAnimationParams(borderWidthPx, borderStrokePx, boundsBuilder, targetView) {
         // Inset the border since we are scaling the container up
-        override val alignmentAdjustmentInset = borderWidthPx
+        override val alignmentAdjustmentInset = borderStrokePx
         override val radiusAdjustment: Float
             // Increase the radius since we are scaling the container up
             get() = alignmentAdjustment
diff --git a/quickstep/src/com/android/quickstep/util/DesksUtils.kt b/quickstep/src/com/android/quickstep/util/DesksUtils.kt
index ccfdbb9..a10f771 100644
--- a/quickstep/src/com/android/quickstep/util/DesksUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/DesksUtils.kt
@@ -16,28 +16,37 @@
 
 package com.android.quickstep.util
 
-import android.content.Context
+import android.app.TaskInfo
+import android.content.ComponentName
+import android.content.res.Resources
+import android.util.Log
 import android.window.DesktopExperienceFlags
 import com.android.systemui.shared.recents.model.Task
 
 class DesksUtils {
     companion object {
+        val sysUiPackage =
+            Resources.getSystem().getString(com.android.internal.R.string.config_systemUi)
+
         @JvmStatic
         fun areMultiDesksFlagsEnabled() =
-            DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue() &&
-                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_FRONTEND.isTrue()
+            DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue &&
+                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_FRONTEND.isTrue
 
         /** Returns true if this [task] contains the [DesktopWallpaperActivity]. */
         @JvmStatic
-        fun isDesktopWallpaperTask(context: Context, task: Task): Boolean {
-            val sysUiPackage =
-                context.getResources().getString(com.android.internal.R.string.config_systemUi)
-            val component = task.key.component
-            if (component != null) {
-                return component.className.contains("DesktopWallpaperActivity") &&
-                    component.packageName.contains(sysUiPackage)
-            }
-            return false
+        fun isDesktopWallpaperTask(task: Task) =
+            task.key.component?.let(::isDesktopWallpaperComponent) == true
+
+        @JvmStatic
+        fun isDesktopWallpaperTask(taskInfo: TaskInfo): Boolean {
+            Log.d("b/403118101", "isDesktopWallpaperTask: $taskInfo")
+            return taskInfo.baseIntent.component?.let(::isDesktopWallpaperComponent) == true
         }
+
+        @JvmStatic
+        fun isDesktopWallpaperComponent(component: ComponentName) =
+            component.className.contains("DesktopWallpaperActivity") &&
+                component.packageName.contains(sysUiPackage)
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.kt b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
index fbe3bc6..7c27293 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.kt
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
@@ -17,22 +17,27 @@
 
 import com.android.quickstep.views.TaskViewType
 import com.android.systemui.shared.recents.model.Task
+import java.util.Objects
 
 /**
  * A [Task] container that can contain N number of tasks that are part of the desktop in recent
- * tasks list. Note that desktops can be empty with no tasks in them. The [deskId] makes sense only
- * when the multiple desks feature is enabled.
+ * tasks list. Note that desktops can be empty with no tasks in them. The [deskId], [displayId]
+ * makes sense only when the multiple desks feature is enabled.
  */
-class DesktopTask(val deskId: Int, tasks: List<Task>) : GroupTask(tasks, TaskViewType.DESKTOP) {
+class DesktopTask(val deskId: Int, val displayId: Int, tasks: List<Task>) :
+    GroupTask(tasks, TaskViewType.DESKTOP) {
 
-    override fun copy() = DesktopTask(deskId, tasks)
+    override fun copy() = DesktopTask(deskId, displayId, tasks)
 
-    override fun toString() = "type=$taskViewType deskId=$deskId tasks=$tasks"
+    override fun toString() = "type=$taskViewType deskId=$deskId displayId=$displayId tasks=$tasks"
 
     override fun equals(o: Any?): Boolean {
         if (this === o) return true
         if (o !is DesktopTask) return false
         if (deskId != o.deskId) return false
+        if (displayId != o.displayId) return false
         return super.equals(o)
     }
+
+    override fun hashCode() = Objects.hash(super.hashCode(), deskId, displayId)
 }
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.kt b/quickstep/src/com/android/quickstep/util/GroupTask.kt
index add8821..2b754e2 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.kt
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.kt
@@ -86,6 +86,8 @@
             return TaskItemInfo(task.task.key.id, wii)
         }
     }
+
+    override fun hashCode() = super.hashCode()
 }
 
 /**
diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
index 843619d..9aded89 100644
--- a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
+++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
@@ -35,8 +35,8 @@
     private final GestureState mGestureState;
 
     @UiThread
-    public InputProxyHandlerFactory(BaseContainerInterface activityInterface,
-            GestureState gestureState) {
+    public InputProxyHandlerFactory(
+            BaseContainerInterface activityInterface, GestureState gestureState) {
         mContainerInterface = activityInterface;
         mGestureState = gestureState;
     }
@@ -47,7 +47,8 @@
     @Override
     public InputConsumer get() {
         RecentsViewContainer container = mContainerInterface.getCreatedContainer();
-        return container == null ? InputConsumer.NO_OP
+        return container == null
+                ? InputConsumer.createNoOpInputConsumer(mGestureState.getDisplayId())
                 : new OverviewInputConsumer(mGestureState, container, null, true);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/BlurUtils.kt b/quickstep/src/com/android/quickstep/views/BlurUtils.kt
new file mode 100644
index 0000000..d6b2a05
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/BlurUtils.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 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 com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur
+import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle
+
+/** Applies blur either behind launcher surface or live tile app. */
+class BlurUtils(private val recentsView: RecentsView<*, *>) {
+
+    fun setDrawLiveTileBelowRecents(drawBelowRecents: Boolean) {
+        val liveTileRemoteTargetHandles =
+            if (
+                recentsView.remoteTargetHandles != null &&
+                    recentsView.recentsAnimationController != null
+            )
+                recentsView.remoteTargetHandles
+            else null
+        setDrawBelowRecents(drawBelowRecents, liveTileRemoteTargetHandles)
+    }
+
+    /**
+     * Set surface in [remoteTargetHandles] to be above or below Recents layer, and update the base
+     * layer to apply blur to in BaseDepthController.
+     */
+    fun setDrawBelowRecents(
+        drawBelowRecents: Boolean,
+        remoteTargetHandles: Array<RemoteTargetHandle>? = null,
+    ) {
+        remoteTargetHandles?.forEach { it.taskViewSimulator.setDrawsBelowRecents(drawBelowRecents) }
+        if (enableOverviewBackgroundWallpaperBlur()) {
+            recentsView.depthController?.setBaseSurfaceOverride(
+                // Blurs behind launcher layer.
+                if (!drawBelowRecents || remoteTargetHandles == null) {
+                    null
+                } else {
+                    // Blurs behind live tile. blur will be applied behind window
+                    // which farthest from user in case of desktop and split apps.
+                    remoteTargetHandles
+                        .maxByOrNull { it.transformParams.targetSet.firstAppTarget.leash.layerId }
+                        ?.transformParams
+                        ?.targetSet
+                        ?.firstAppTarget
+                        ?.leash
+                }
+            )
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 27657b4..8876633 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -25,6 +25,7 @@
 import android.util.AttributeSet
 import android.util.Log
 import android.util.Size
+import android.view.Display.INVALID_DISPLAY
 import android.view.Gravity
 import android.view.View
 import android.view.ViewStub
@@ -59,6 +60,7 @@
 import com.android.quickstep.task.thumbnail.TaskThumbnailView
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.RecentsOrientedState
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.enableMultipleDesktops
 import kotlin.math.roundToInt
 
 /** TaskView that contains all tasks that are part of the desktop. */
@@ -69,7 +71,10 @@
         type = TaskViewType.DESKTOP,
         thumbnailFullscreenParams = DesktopFullscreenDrawParams(context),
     ) {
-    var deskId = DesktopVisibilityController.INACTIVE_DESK_ID
+    val deskId
+        get() = desktopTask?.deskId ?: DesktopVisibilityController.INACTIVE_DESK_ID
+
+    private var desktopTask: DesktopTask? = null
 
     private val contentViewFullscreenParams = FullscreenDrawParams(context)
 
@@ -112,6 +117,14 @@
             positionTaskWindows()
         }
 
+    override val displayId: Int
+        get() =
+            if (enableMultipleDesktops(context)) {
+                desktopTask?.displayId ?: INVALID_DISPLAY
+            } else {
+                super.displayId
+            }
+
     private fun getRemoteTargetHandle(taskId: Int): RemoteTargetHandle? =
         remoteTargetHandles?.firstOrNull {
             it.transformParams.targetSet.firstAppTargetTaskId == taskId
@@ -284,7 +297,7 @@
         orientedState: RecentsOrientedState,
         taskOverlayFactory: TaskOverlayFactory,
     ) {
-        deskId = desktopTask.deskId
+        this.desktopTask = desktopTask
         // TODO(b/370495260): Minimized tasks should not be filtered with desktop exploded view
         // support.
         // Minimized tasks should not be shown in Overview.
@@ -336,7 +349,7 @@
 
     override fun onRecycle() {
         super.onRecycle()
-        deskId = DesktopVisibilityController.INACTIVE_DESK_ID
+        desktopTask = null
         explodeProgress = 0.0f
         viewModel = null
         visibility = VISIBLE
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 71a4dde..10a2e90 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -182,7 +182,6 @@
         val splitBoundsConfig = splitBoundsConfig ?: return
         val deviceProfile = container.deviceProfile
         val taskIconHeight = deviceProfile.overviewTaskIconSizePx
-        val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
         val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
         var oneIconHiddenDueToSmallWidth = false
 
@@ -211,6 +210,7 @@
         }
 
         if (enableOverviewIconMenu()) {
+            val isDeviceRtl = Utilities.isRtl(resources)
             val groupedTaskViewSizes =
                 pagedOrientationHandler.getGroupedTaskViewSizes(
                     deviceProfile,
@@ -226,7 +226,7 @@
                 groupedTaskViewSizes.first.y,
                 layoutParams.height,
                 layoutParams.width,
-                isRtl,
+                isDeviceRtl,
                 deviceProfile,
                 splitBoundsConfig,
                 inSplitSelection,
@@ -241,7 +241,7 @@
                 leftTopTaskContainer.taskContentView.measuredHeight,
                 measuredHeight,
                 measuredWidth,
-                isRtl,
+                isLayoutRtl,
                 deviceProfile,
                 splitBoundsConfig,
                 inSplitSelection,
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.kt b/quickstep/src/com/android/quickstep/views/IconAppChipView.kt
index c20aa11..7683a15 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.kt
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.kt
@@ -122,6 +122,9 @@
             field = max(value, minMaxWidth)
         }
 
+    var isExpanded: Boolean = false
+        private set
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         iconView = findViewById(R.id.icon_view)
@@ -356,6 +359,7 @@
                 ObjectAnimator.ofFloat(iconArrowView, SCALE_Y, -1f),
             )
             animator!!.setDuration(MENU_BACKGROUND_REVEAL_DURATION.toLong())
+            isExpanded = true
         } else {
             // Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu
             val expandedTextClipAnim =
@@ -390,6 +394,7 @@
                 ObjectAnimator.ofFloat(iconArrowView, SCALE_Y, 1f),
             )
             animator!!.setDuration(MENU_BACKGROUND_HIDE_DURATION.toLong())
+            isExpanded = false
         }
 
         if (!animated) animator!!.duration = 0
@@ -416,6 +421,17 @@
         }
     }
 
+    override fun focusSearch(direction: Int): View? {
+        if (mParent == null) return null
+        return when (direction) {
+            FOCUS_RIGHT,
+            FOCUS_DOWN -> mParent.focusSearch(this, View.FOCUS_FORWARD)
+            FOCUS_UP,
+            FOCUS_LEFT -> mParent.focusSearch(this, View.FOCUS_BACKWARD)
+            else -> super.focusSearch(direction)
+        }
+    }
+
     override fun asView(): View = this
 
     private companion object {
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 0f1c294..74de2ac 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -19,6 +19,7 @@
 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
 
 import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
+import static com.android.launcher3.LauncherState.ADD_DESK_BUTTON;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
@@ -184,10 +185,8 @@
         if (finalState.isRecentsViewVisible && finalState != OVERVIEW_MODAL_TASK) {
             setTaskBorderEnabled(true);
         }
-
         if (isOverlayEnabled) {
-            runActionOnRemoteHandles(remoteTargetHandle ->
-                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
+            mBlurUtils.setDrawLiveTileBelowRecents(true);
         }
     }
 
@@ -198,7 +197,10 @@
             LauncherState state = getStateManager().getState();
             boolean hasClearAllButton = (state.getVisibleElements(mContainer)
                     & CLEAR_ALL_BUTTON) != 0;
+            boolean hasAddDeskButton = (state.getVisibleElements(mContainer)
+                    & ADD_DESK_BUTTON) != 0;
             setDisallowScrollToClearAll(!hasClearAllButton);
+            setDisallowScrollToAddDesk(!hasAddDeskButton);
         }
     }
 
@@ -276,7 +278,7 @@
         GestureState.GestureEndTarget endTarget = mCurrentGestureEndTarget;
         if (endTarget == GestureState.GestureEndTarget.LAST_TASK
                 && desktopVisibilityController.isInDesktopModeAndNotInOverview(
-                        mContainer.getDisplayId())) {
+                mContainer.getDisplayId())) {
             // Recents gesture was cancelled and we are returning to the previous task.
             // After super class has handled clean up, show desktop apps on top again
             showDesktopApps = true;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt
index 4ce18f5..d39b528 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt
@@ -96,63 +96,86 @@
                     onEndRunnable()
                 }
         if (!isDismissing) {
-            addNeighboringSpringAnimationsForDismissCancel(
+            addNeighborSettlingSpringAnimations(
                 draggedTaskView,
                 draggedTaskViewSpringAnimation,
+                driverProgressThreshold = 0f,
+                isSpringDirectionVertical = true,
             )
         }
         return draggedTaskViewSpringAnimation
     }
 
-    private fun addNeighboringSpringAnimationsForDismissCancel(
+    private fun addNeighborSettlingSpringAnimations(
         draggedTaskView: TaskView,
-        draggedTaskViewSpringAnimation: SpringAnimation,
+        springAnimationDriver: SpringAnimation,
+        tasksToExclude: List<TaskView> = emptyList(),
+        driverProgressThreshold: Float,
+        isSpringDirectionVertical: Boolean,
     ) {
         // Empty spring animation exists for conditional start, and to drive neighboring springs.
         val neighborsToSettle =
             SpringAnimation(FloatValueHolder()).setSpring(createExpressiveDismissSpringForce())
-        var lastPosition = 0f
-        var startSettling = false
-        draggedTaskViewSpringAnimation.addUpdateListener { _, value, velocity ->
-            // Start the settling animation the first time the dragged task passes the origin (from
-            // negative displacement to positive displacement). We do not check for an exact value
-            // to compare to, as the update listener does not necessarily hit every value (e.g. a
-            // value of zero). Do not check again once it has started settling, as a spring can
-            // bounce past the origin multiple times depending on the stiffness and damping ratio.
-            if (startSettling) return@addUpdateListener
-            if (lastPosition < 0 && value >= 0) {
-                startSettling = true
-            }
-            lastPosition = value
-            if (startSettling) {
-                neighborsToSettle.setStartVelocity(velocity).animateToFinalPosition(0f)
-                playDismissSettlingHaptic(velocity)
-            }
-        }
+        addThresholdSpringAnimationTrigger(
+            springAnimationDriver,
+            progressThreshold = driverProgressThreshold,
+            neighborsToSettle,
+        )
 
         // Add tasks before dragged index, fanning out from the dragged task.
         // The order they are added matters, as each spring drives the next.
         var previousNeighbor = neighborsToSettle
-        getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = true).forEach {
-            (taskView, offset) ->
-            previousNeighbor =
-                createNeighboringTaskViewSpringAnimation(
-                    taskView,
-                    offset * ADDITIONAL_DISMISS_DAMPING_RATIO,
-                    previousNeighbor,
-                )
-        }
+        getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = true)
+            .filter { (taskView, _) -> !tasksToExclude.contains(taskView) }
+            .forEach { (taskView, offset) ->
+                previousNeighbor =
+                    createNeighboringTaskViewSpringAnimation(
+                        taskView,
+                        offset * ADDITIONAL_DISMISS_DAMPING_RATIO,
+                        previousNeighbor,
+                        isSpringDirectionVertical,
+                    )
+            }
         // Add tasks after dragged index, fanning out from the dragged task.
         // The order they are added matters, as each spring drives the next.
         previousNeighbor = neighborsToSettle
-        getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = false).forEach {
-            (taskView, offset) ->
-            previousNeighbor =
-                createNeighboringTaskViewSpringAnimation(
-                    taskView,
-                    offset * ADDITIONAL_DISMISS_DAMPING_RATIO,
-                    previousNeighbor,
-                )
+        getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = false)
+            .filter { (taskView, _) -> !tasksToExclude.contains(taskView) }
+            .forEach { (taskView, offset) ->
+                previousNeighbor =
+                    createNeighboringTaskViewSpringAnimation(
+                        taskView,
+                        offset * ADDITIONAL_DISMISS_DAMPING_RATIO,
+                        previousNeighbor,
+                        isSpringDirectionVertical,
+                    )
+            }
+    }
+
+    /** As spring passes threshold for the first time, run conditional spring with velocity. */
+    private fun addThresholdSpringAnimationTrigger(
+        springAnimationDriver: SpringAnimation,
+        progressThreshold: Float,
+        conditionalSpring: SpringAnimation,
+    ) {
+        var lastPosition = 0f
+        var startSettling = false
+        springAnimationDriver.addUpdateListener { _, value, velocity ->
+            // We do not compare to the threshold directly, as the update listener
+            // does not necessarily hit every value. Do not check again once it has started
+            // settling, as a spring can bounce past the end value multiple times.
+            if (startSettling) return@addUpdateListener
+            if (
+                lastPosition < progressThreshold && value >= progressThreshold ||
+                    lastPosition > progressThreshold && value <= progressThreshold
+            ) {
+                startSettling = true
+            }
+            lastPosition = value
+            if (startSettling) {
+                conditionalSpring.setStartVelocity(velocity).animateToFinalPosition(0f)
+                playDismissSettlingHaptic(velocity)
+            }
         }
     }
 
@@ -208,21 +231,25 @@
         taskView: TaskView,
         dampingOffsetRatio: Float,
         previousNeighborSpringAnimation: SpringAnimation,
+        springingDirectionVertical: Boolean,
     ): SpringAnimation {
+        val springProperty =
+            if (springingDirectionVertical) taskView.secondaryDismissTranslationProperty
+            else taskView.primaryDismissTranslationProperty
         val neighboringTaskViewSpringAnimation =
-            SpringAnimation(
-                    taskView,
-                    FloatPropertyCompat.createFloatPropertyCompat(
-                        taskView.secondaryDismissTranslationProperty
-                    ),
-                )
+            SpringAnimation(taskView, FloatPropertyCompat.createFloatPropertyCompat(springProperty))
                 .setSpring(createExpressiveDismissSpringForce(dampingOffsetRatio))
         // Update live tile on spring animation.
         if (taskView.isRunningTask && recentsView.enableDrawingLiveTile) {
             neighboringTaskViewSpringAnimation.addUpdateListener { _, _, _ ->
                 recentsView.runActionOnRemoteHandles { remoteTargetHandle ->
-                    remoteTargetHandle.taskViewSimulator.taskSecondaryTranslation.value =
-                        taskView.secondaryDismissTranslationProperty.get(taskView)
+                    val taskTranslation =
+                        if (springingDirectionVertical) {
+                            remoteTargetHandle.taskViewSimulator.taskSecondaryTranslation
+                        } else {
+                            remoteTargetHandle.taskViewSimulator.taskPrimaryTranslation
+                        }
+                    taskTranslation.value = springProperty.get(taskView)
                 }
                 recentsView.redrawLiveTile()
             }
@@ -271,7 +298,7 @@
             .playToken(
                 MSDLToken.CANCEL,
                 InteractionProperties.DynamicVibrationScale(
-                    boundToRange(velocity / maxDismissSettlingVelocity, 0f, 1f),
+                    boundToRange(abs(velocity) / maxDismissSettlingVelocity, 0f, 1f),
                     VibrationAttributes.Builder()
                         .setUsage(VibrationAttributes.USAGE_TOUCH)
                         .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT)
@@ -319,32 +346,39 @@
                 .setSpring(createExpressiveGridReflowSpringForce(finalPosition = dismissedTaskGap))
         val towardsStart = if (recentsView.isRtl) dismissedTaskGap < 0 else dismissedTaskGap > 0
 
+        var tasksToReflow: List<TaskView>
         // Build the chains of Spring Animations
         when {
             !recentsView.showAsGrid() -> {
-                buildDismissReflowSpringAnimationChain(
+                tasksToReflow =
                     getTasksToReflow(
                         recentsView.mUtils.taskViews.toList(),
                         dismissedTaskView,
                         towardsStart,
-                    ),
+                    )
+                buildDismissReflowSpringAnimationChain(
+                    tasksToReflow,
                     dismissedTaskGap,
                     previousSpring = springAnimationDriver,
                 )
             }
             dismissedTaskView.isLargeTile -> {
+                tasksToReflow =
+                    getTasksToReflow(
+                        recentsView.mUtils.getLargeTaskViews(),
+                        dismissedTaskView,
+                        towardsStart,
+                    )
                 val lastSpringAnimation =
                     buildDismissReflowSpringAnimationChain(
-                        getTasksToReflow(
-                            recentsView.mUtils.getLargeTaskViews(),
-                            dismissedTaskView,
-                            towardsStart,
-                        ),
+                        tasksToReflow,
                         dismissedTaskGap,
                         previousSpring = springAnimationDriver,
                     )
                 // Add all top and bottom grid tasks when animating towards the end of the grid.
                 if (!towardsStart) {
+                    tasksToReflow += recentsView.mUtils.getTopRowTaskViews()
+                    tasksToReflow += recentsView.mUtils.getBottomRowTaskViews()
                     buildDismissReflowSpringAnimationChain(
                         recentsView.mUtils.getTopRowTaskViews(),
                         dismissedTaskGap,
@@ -358,29 +392,43 @@
                 }
             }
             recentsView.isOnGridBottomRow(dismissedTaskView) -> {
-                buildDismissReflowSpringAnimationChain(
+                tasksToReflow =
                     getTasksToReflow(
                         recentsView.mUtils.getBottomRowTaskViews(),
                         dismissedTaskView,
                         towardsStart,
-                    ),
+                    )
+                buildDismissReflowSpringAnimationChain(
+                    tasksToReflow,
                     dismissedTaskGap,
                     previousSpring = springAnimationDriver,
                 )
             }
             else -> {
-                buildDismissReflowSpringAnimationChain(
+                tasksToReflow =
                     getTasksToReflow(
                         recentsView.mUtils.getTopRowTaskViews(),
                         dismissedTaskView,
                         towardsStart,
-                    ),
+                    )
+                buildDismissReflowSpringAnimationChain(
+                    tasksToReflow,
                     dismissedTaskGap,
                     previousSpring = springAnimationDriver,
                 )
             }
         }
 
+        if (tasksToReflow.isNotEmpty()) {
+            addNeighborSettlingSpringAnimations(
+                dismissedTaskView,
+                springAnimationDriver,
+                tasksToExclude = tasksToReflow,
+                driverProgressThreshold = dismissedTaskGap,
+                isSpringDirectionVertical = false,
+            )
+        }
+
         // Start animations and remove the dismissed task at the end, dismiss immediately if no
         // neighboring tasks exist.
         val runGridEndAnimationAndRelayout = {
@@ -429,8 +477,8 @@
                 else -> 1f
             } * (if (recentsView.isRtl) 1f else -1f)
 
-        return (dismissedTaskView.layoutParams.width + recentsView.pageSpacing) *
-            dismissHorizontalFactor
+        return (recentsView.pagedOrientationHandler.getPrimarySize(dismissedTaskView) +
+            recentsView.pageSpacing) * dismissHorizontalFactor
     }
 
     private fun getTasksToReflow(
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bb2aa75..8c7fe26 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -17,6 +17,8 @@
 package com.android.quickstep.views;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.os.Trace.traceBegin;
+import static android.os.Trace.traceEnd;
 import static android.view.Surface.ROTATION_0;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
@@ -32,14 +34,13 @@
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.app.animation.Interpolators.clampToProgress;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
-import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
-import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
 import static com.android.launcher3.Flags.enableDesktopExplodedView;
 import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile;
+import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur;
 import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.Flags.enableSeparateExternalDisplayTasks;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
@@ -56,6 +57,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
+import static com.android.launcher3.statehandlers.DesktopVisibilityController.INACTIVE_DESK_ID;
 import static com.android.launcher3.testing.shared.TestProtocol.DISMISS_ANIMATION_ENDS_MESSAGE;
 import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -64,6 +66,7 @@
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.quickstep.BaseContainerInterface.getTaskDimension;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+import static com.android.quickstep.util.DesksUtils.areMultiDesksFlagsEnabled;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
 import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
@@ -102,6 +105,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.text.Layout;
@@ -212,7 +216,6 @@
 import com.android.quickstep.recents.viewmodel.RecentsViewModel;
 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
 import com.android.quickstep.util.AnimUtils;
-import com.android.quickstep.util.DesksUtils;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LayoutUtils;
@@ -584,6 +587,8 @@
     private final TaskOverlayFactory mTaskOverlayFactory;
 
     protected boolean mDisallowScrollToClearAll;
+    // True if it is not allowed to scroll to [AddDesktopButton].
+    protected boolean mDisallowScrollToAddDesk;
     private boolean mOverlayEnabled;
     protected boolean mFreezeViewVisibility;
     private boolean mOverviewGridEnabled;
@@ -827,7 +832,7 @@
                     mOrientationState.setMultiWindowMode(inMultiWindowMode);
                     setLayoutRotation(mOrientationState.getTouchRotation(),
                             mOrientationState.getDisplayRotation());
-                    updateChildTaskOrientations();
+                    mUtils.updateChildTaskOrientations();
                     if (!inMultiWindowMode && mOverviewStateEnabled) {
                         // TODO: Re-enable layout transitions for addition of the unpinned task
                         reloadIfNeeded();
@@ -863,6 +868,9 @@
     private final Matrix mTmpMatrix = new Matrix();
 
     private int mTaskViewCount = 0;
+
+    protected final BlurUtils mBlurUtils = new BlurUtils(this);
+
     @Nullable
     public TaskView getFirstTaskView() {
         return mUtils.getFirstTaskView();
@@ -1291,6 +1299,7 @@
 
     @Override
     public void onViewRemoved(View child) {
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewRemoved");
         super.onViewRemoved(child);
         // Clear the task data for the removed child if it was visible unless:
         // - It's the initial taskview for entering split screen, we only pretend to dismiss the
@@ -1302,6 +1311,7 @@
                 clearAndRecycleTaskView((TaskView) child);
             }
         }
+        traceEnd(Trace.TRACE_TAG_APP);
     }
 
     private void clearAndRecycleTaskView(TaskView taskView) {
@@ -1320,6 +1330,7 @@
 
     @Override
     public void onViewAdded(View child) {
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewAdded");
         super.onViewAdded(child);
         if (child instanceof TaskView) {
             mTaskViewCount++;
@@ -1330,6 +1341,7 @@
         child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL);
         mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false);
         updateEmptyMessage();
+        traceEnd(Trace.TRACE_TAG_APP);
     }
 
     @Override
@@ -1926,14 +1938,19 @@
             return;
         }
 
-        // TODO: b/400532675 - The use of `currentTaskIds`, `runningTaskIds`, and `focusedTaskIds`
-        // needs to be audited so that they can work with empty desks that have no tasks.
-        int[] currentTaskIds;
+        // Start here to avoid early returns and empty cases which have special logic
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan");
+
         TaskView currentTaskView = getTaskViewAt(mCurrentPage);
-        if (currentTaskView != null) {
+        int[] currentTaskIds = null;
+        // Track the current DesktopTaskView through [deskId] as a desk can be empty without any
+        // tasks.
+        int currentTaskViewDeskId = INACTIVE_DESK_ID;
+        if (areMultiDesksFlagsEnabled()
+                && currentTaskView instanceof DesktopTaskView desktopTaskView) {
+            currentTaskViewDeskId = desktopTaskView.getDeskId();
+        } else if (currentTaskView != null) {
             currentTaskIds = currentTaskView.getTaskIds();
-        } else {
-            currentTaskIds = new int[0];
         }
 
         // Unload existing visible task data
@@ -1945,9 +1962,19 @@
 
         // 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[] runningTaskIds = getTaskIdsForTaskViewId(mRunningTaskViewId);
-        int[] focusedTaskIds = getTaskIdsForTaskViewId(mFocusedTaskViewId);
+        TaskView runningTaskView = getRunningTaskView();
+        int[] runningTaskIds = null;
 
+        // Track the running TaskView through [deskId] as a desk can be empty without any tasks.
+        int runningTaskViewDeskId = INACTIVE_DESK_ID;
+        if (areMultiDesksFlagsEnabled()
+                && runningTaskView instanceof DesktopTaskView desktopTaskView) {
+            runningTaskViewDeskId = desktopTaskView.getDeskId();
+        } else if (runningTaskView != null) {
+            runningTaskIds = runningTaskView.getTaskIds();
+        }
+
+        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.
         setFocusedTaskViewId(INVALID_TASK_ID);
@@ -1959,8 +1986,9 @@
         // TaskIds will no longer be valid after remove and re-add, clearing mTopRowIdSet.
         mAnyTaskHasBeenDismissed = false;
         mTopRowIdSet.clear();
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.removeAllViews");
         removeAllViews();
-
+        traceEnd(Trace.TRACE_TAG_APP);
         // If we are entering Overview as a result of initiating a split from somewhere else
         // (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail.
         int stagedTaskIdToBeRemoved;
@@ -1987,6 +2015,7 @@
             // Add `mAddDesktopButton` as the first child.
             addView(mAddDesktopButton);
         }
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop");
 
         // Add views as children based on whether it's grouped or single task. Looping through
         // taskGroups backwards populates the thumbnail grid from least recent to most recent.
@@ -2006,8 +2035,11 @@
 
             // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
             // to be a temporary container for the remaining task.
+            traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.createTaskView");
             TaskView taskView = getTaskViewFromPool(
                     containsStagedTask ? TaskViewType.SINGLE : groupTask.taskViewType);
+            traceEnd(Trace.TRACE_TAG_APP);
+            traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.bind");
             if (taskView instanceof GroupedTaskView groupedTaskView) {
                 var splitTask = (SplitTask) groupTask;
                 groupedTaskView.bind(splitTask.getTopLeftTask(),
@@ -2025,13 +2057,18 @@
                 taskView.bind(((SingleTask) groupTask).getTask(), mOrientationState,
                         mTaskOverlayFactory);
             }
+            traceEnd(Trace.TRACE_TAG_APP);
+            traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.addTaskView");
             addView(taskView);
+            traceEnd(Trace.TRACE_TAG_APP);
 
             // enables instance filtering if the feature flag for it is on
             if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
                 taskView.setUpShowAllInstancesListener();
             }
         }
+        // For loop end trace
+        traceEnd(Trace.TRACE_TAG_APP);
 
         addView(mClearAllButton);
 
@@ -2051,27 +2088,29 @@
         setFocusedTaskViewId(
                 newFocusedTaskView != null ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID);
 
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.layouts");
         updateTaskSize();
-        updateChildTaskOrientations();
+        mUtils.updateChildTaskOrientations();
+        traceEnd(Trace.TRACE_TAG_APP);
 
-        TaskView newRunningTaskView = null;
-        if (hasAllValidTaskIds(runningTaskIds)) {
+        TaskView newRunningTaskView = mUtils.getDesktopTaskViewForDeskId(runningTaskViewDeskId);
+        if (newRunningTaskView == null) {
             // Update mRunningTaskViewId to be the new TaskView that was assigned by binding
             // the full list of tasks to taskViews
             newRunningTaskView = getTaskViewByTaskIds(runningTaskIds);
-            if (newRunningTaskView != null) {
-                setRunningTaskViewId(newRunningTaskView.getTaskViewId());
+        }
+        if (newRunningTaskView != null) {
+            setRunningTaskViewId(newRunningTaskView.getTaskViewId());
+        } else {
+            if (mActiveGestureRunningTasks != null) {
+                // This will update mRunningTaskViewId and create a stub view if necessary.
+                // We try to avoid this because it can cause a scroll jump, but it is needed
+                // for cases where the running task isn't included in this load plan (e.g. if
+                // the current running task is excludedFromRecents.)
+                showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan");
+                newRunningTaskView = getRunningTaskView();
             } else {
-                if (mActiveGestureRunningTasks != null) {
-                    // This will update mRunningTaskViewId and create a stub view if necessary.
-                    // We try to avoid this because it can cause a scroll jump, but it is needed
-                    // for cases where the running task isn't included in this load plan (e.g. if
-                    // the current running task is excludedFromRecents.)
-                    showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan");
-                    newRunningTaskView = getRunningTaskView();
-                } else {
-                    setRunningTaskViewId(INVALID_TASK_ID);
-                }
+                setRunningTaskViewId(INVALID_TASK_ID);
             }
         }
 
@@ -2079,11 +2118,12 @@
         if (mNextPage != INVALID_PAGE) {
             // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
             mCurrentPage = previousCurrentPage;
-            if (hasAllValidTaskIds(currentTaskIds)) {
+            currentTaskView = mUtils.getDesktopTaskViewForDeskId(currentTaskViewDeskId);
+            if (currentTaskView == null) {
                 currentTaskView = getTaskViewByTaskIds(currentTaskIds);
-                if (currentTaskView != null) {
-                    targetPage = indexOfChild(currentTaskView);
-                }
+            }
+            if (currentTaskView != null) {
+                targetPage = indexOfChild(currentTaskView);
             }
         } else if (previousFocusedPage != INVALID_PAGE) {
             targetPage = previousFocusedPage;
@@ -2106,6 +2146,7 @@
             });
         }
 
+        traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.cleanupStates");
         if (mIgnoreResetTaskId != INVALID_TASK_ID &&
                 getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) {
             // If the taskView mapping is changing, do not preserve the visuals. Since we are
@@ -2120,6 +2161,10 @@
         if (isPageScrollsInitialized()) {
             onPageScrollsInitialized();
         }
+        traceEnd(Trace.TRACE_TAG_APP);
+
+        // applyLoadPlan end trace
+        traceEnd(Trace.TRACE_TAG_APP);
     }
 
     private boolean isModal() {
@@ -2297,7 +2342,7 @@
         updateSizeAndPadding();
 
         // Update TaskView's DeviceProfile dependent layout.
-        updateChildTaskOrientations();
+        mUtils.updateChildTaskOrientations();
 
         requestLayout();
         // Reapply the current page to update page scrolls.
@@ -2705,9 +2750,7 @@
             }
             setEnableDrawingLiveTile(false);
         }
-        runActionOnRemoteHandles(remoteTargetHandle ->
-                remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
-
+        mBlurUtils.setDrawLiveTileBelowRecents(false);
         // These are relatively expensive and don't need to be done this frame (RecentsView isn't
         // visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
         post(this::onReset);
@@ -2907,22 +2950,6 @@
         return as;
     }
 
-    private void updateChildTaskOrientations() {
-        for (TaskView taskView : getTaskViews()) {
-            taskView.setOrientationState(mOrientationState);
-        }
-        boolean shouldRotateMenuForFakeRotation =
-                !mOrientationState.isRecentsActivityRotationAllowed();
-        if (!shouldRotateMenuForFakeRotation) {
-            return;
-        }
-        AbstractFloatingView floatingView = getTopOpenViewWithType(mContainer, TYPE_TASK_MENU);
-        if (floatingView instanceof TaskMenuView taskMenuView) {
-            // Rotation is supported on phone (details at b/254198019#comment4)
-            taskMenuView.onRotationChanged();
-        }
-    }
-
     /**
      * Called when a gesture from an app has finished, and an end target has been determined.
      */
@@ -3079,7 +3106,8 @@
 
         // TODO: b/401582344 - Implement a way to exclude the `DesktopWallpaperActivity`.
         desktopTaskView.bind(
-                new DesktopTask(activeDeskId, Arrays.asList(runningTasks)),
+                new DesktopTask(activeDeskId, mContainer.getDisplayId(),
+                        Arrays.asList(runningTasks)),
                 mOrientationState, mTaskOverlayFactory);
         return desktopTaskView;
     }
@@ -3159,7 +3187,7 @@
         setRunningTaskHidden(runningTaskTileHidden);
         // Update task size after setting current task.
         updateTaskSize();
-        updateChildTaskOrientations();
+        mUtils.updateChildTaskOrientations();
 
         // Reload the task list
         reloadIfNeeded();
@@ -4312,7 +4340,7 @@
                             finalNextFocusedTaskView.getDismissIconFadeInAnimator().start();
                         }
                         updateTaskSize();
-                        updateChildTaskOrientations();
+                        mUtils.updateChildTaskOrientations();
                         // Update scroll and snap to page.
                         updateScrollSynchronously();
 
@@ -4565,7 +4593,7 @@
     }
 
     private void removeDesktopTaskView(DesktopTaskView desktopTaskView) {
-        if (DesksUtils.areMultiDesksFlagsEnabled()) {
+        if (areMultiDesksFlagsEnabled()) {
             SystemUiProxy.INSTANCE
                     .get(getContext())
                     .removeDesk(desktopTaskView.getDeskId());
@@ -4738,6 +4766,11 @@
         if (isHandlingTouch() || event.getAction() != KeyEvent.ACTION_DOWN) {
             return super.dispatchKeyEvent(event);
         }
+
+        if (mUtils.shouldInterceptKeyEvent(event)) {
+            return super.dispatchKeyEvent(event);
+        }
+
         switch (event.getKeyCode()) {
             case KeyEvent.KEYCODE_TAB:
                 return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
@@ -5772,12 +5805,10 @@
                     // above RecentsView to avoid wallpaper blur from being applied to it.
                     if (!taskView.isRunningTask()) {
                         runActionOnRemoteHandles(
-                                remoteTargetHandle -> {
-                                    remoteTargetHandle.getTaskViewSimulator().setPivotOverride(
-                                            mTempPointF);
-                                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(
-                                            false);
-                                });
+                                remoteTargetHandle ->
+                                        remoteTargetHandle.getTaskViewSimulator()
+                                                .setPivotOverride(mTempPointF));
+                        mBlurUtils.setDrawLiveTileBelowRecents(false);
                     }
                 }
 
@@ -5912,8 +5943,7 @@
         mPendingAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                runActionOnRemoteHandles(remoteTargetHandle ->
-                        remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
+                mBlurUtils.setDrawLiveTileBelowRecents(false);
             }
         });
         mPendingAnimation.addEndListener(isSuccess -> {
@@ -5951,8 +5981,7 @@
             // If launch animation didn't complete i.e. user dragged live tile down and then
             // back up and returned to Overview, then we need to ensure we reset the
             // view to draw below recents so that it can't be interacted with.
-            runActionOnRemoteHandles(remoteTargetHandle ->
-                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
+            mBlurUtils.setDrawLiveTileBelowRecents(true);
             redrawLiveTile();
         }
         return Unit.INSTANCE;
@@ -6031,6 +6060,7 @@
         });
     }
 
+    @Nullable
     public RemoteTargetHandle[] getRemoteTargetHandles() {
         return mRemoteTargetHandles;
     }
@@ -6184,6 +6214,9 @@
         mRecentsAnimationController = null;
         mSplitSelectStateController.setRecentsAnimationRunning(false);
         executeSideTaskLaunchCallback();
+        if (enableOverviewBackgroundWallpaperBlur()) {
+            mBlurUtils.setDrawLiveTileBelowRecents(false);
+        }
     }
 
     public void setDisallowScrollToClearAll(boolean disallowScrollToClearAll) {
@@ -6192,6 +6225,17 @@
             updateMinAndMaxScrollX();
         }
     }
+    /**
+     * Update the value of [mDisallowScrollToAddDesk]
+     */
+    public void setDisallowScrollToAddDesk(boolean disallowScrollToAddDesk) {
+        if (mDisallowScrollToAddDesk != disallowScrollToAddDesk) {
+            mDisallowScrollToAddDesk = disallowScrollToAddDesk;
+            updateMinAndMaxScrollX();
+        }
+    }
+
+
 
     /**
      * Updates page scroll synchronously after measure and layout child views.
@@ -6337,7 +6381,20 @@
         if (addDesktopButtonIndex >= 0 && addDesktopButtonIndex < outPageScrolls.length) {
             int firstViewIndex = getFirstViewIndex();
             if (firstViewIndex >= 0 && firstViewIndex < outPageScrolls.length) {
-                outPageScrolls[addDesktopButtonIndex] = outPageScrolls[firstViewIndex];
+                // If we can scroll to [AddDesktopButton], make its page scroll equal to
+                // the first [TaskView]. Otherwise, make its page scroll out of range of
+                // [minScroll, maxScroll].
+                if (!mDisallowScrollToAddDesk) {
+                    outPageScrolls[addDesktopButtonIndex] = outPageScrolls[firstViewIndex];
+                } else {
+                    outPageScrolls[addDesktopButtonIndex] =
+                            outPageScrolls[firstViewIndex] + (mIsRtl ? 1 : -1);
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "getPageScrolls - addDesktopButtonScroll: "
+                        + outPageScrolls[addDesktopButtonIndex]);
             }
         }
         if (DEBUG) {
@@ -6979,7 +7036,7 @@
         // `AddNewDesktopButton`.
         DesktopTaskView desktopTaskView =
                 (DesktopTaskView) getTaskViewFromPool(TaskViewType.DESKTOP);
-        desktopTaskView.bind(new DesktopTask(deskId, new ArrayList<>()),
+        desktopTaskView.bind(new DesktopTask(deskId, displayId, new ArrayList<>()),
                 mOrientationState, mTaskOverlayFactory);
 
         Objects.requireNonNull(mAddDesktopButton);
@@ -6987,7 +7044,7 @@
         addView(desktopTaskView, insertionIndex);
 
         updateTaskSize();
-        updateChildTaskOrientations();
+        mUtils.updateChildTaskOrientations();
 
         // TODO: b/401002178 - Recalculate the new current page such that the addition of the new
         //  desk does not result in a change in the current scroll page.
@@ -7139,4 +7196,15 @@
     public interface TaskLaunchListener {
         void onTaskLaunched();
     }
+
+    /**
+     * Sets whether the remote animation targets should draw below the recents view.
+     *
+     * @param drawBelowRecents  whether the surface should draw below Recents.
+     * @param remoteTargetHandles collection of remoteTargetHandles in Recents.
+     */
+    public void setDrawBelowRecents(boolean drawBelowRecents,
+            RemoteTargetHandle[] remoteTargetHandles) {
+        mBlurUtils.setDrawBelowRecents(drawBelowRecents, remoteTargetHandles);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
index 037bef6..9c35913 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -18,14 +18,20 @@
 
 import android.graphics.Rect
 import android.util.FloatProperty
+import android.view.KeyEvent
 import android.view.View
+import android.view.View.LAYOUT_DIRECTION_LTR
+import android.view.View.LAYOUT_DIRECTION_RTL
 import androidx.core.view.children
+import com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU
+import com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType
 import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.launcher3.Flags.enableOverviewIconMenu
 import com.android.launcher3.Flags.enableSeparateExternalDisplayTasks
 import com.android.launcher3.statehandlers.DesktopVisibilityController
 import com.android.launcher3.statehandlers.DesktopVisibilityController.Companion.INACTIVE_DESK_ID
 import com.android.launcher3.util.IntArray
-import com.android.quickstep.util.DesksUtils
+import com.android.quickstep.util.DesksUtils.Companion.areMultiDesksFlagsEnabled
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.GroupTask
 import com.android.quickstep.util.isExternalDisplay
@@ -57,7 +63,7 @@
      */
     fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
         var (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
-        if (DesksUtils.areMultiDesksFlagsEnabled()) {
+        if (areMultiDesksFlagsEnabled()) {
             // Desk IDs of newer desks are larger than those of older desks, hence we can use them
             // to sort desks from old to new.
             desktopTasks = desktopTasks.sortedBy { (it as DesktopTask).deskId }
@@ -165,6 +171,17 @@
     private fun getDeviceProfile() = (recentsView.mContainer as RecentsViewContainer).deviceProfile
 
     fun getRunningTaskExpectedIndex(runningTaskView: TaskView): Int {
+        if (areMultiDesksFlagsEnabled() && runningTaskView is DesktopTaskView) {
+            // Use the [deskId] to keep desks in the order of their creation, as a newer desk
+            // always has a larger [deskId] than the older desks.
+            val desktopTaskView =
+                taskViews.firstOrNull {
+                    it is DesktopTaskView &&
+                        it.deskId != INACTIVE_DESK_ID &&
+                        it.deskId <= runningTaskView.deskId
+                }
+            if (desktopTaskView != null) return recentsView.indexOfChild(desktopTaskView)
+        }
         val firstTaskViewIndex = recentsView.indexOfChild(getFirstTaskView())
         return if (getDeviceProfile().isTablet) {
             var index = firstTaskViewIndex
@@ -343,6 +360,33 @@
         }
     }
 
+    private fun getTaskMenu(): TaskMenuView? =
+        getTopOpenViewWithType(recentsView.mContainer, TYPE_TASK_MENU) as? TaskMenuView
+
+    fun shouldInterceptKeyEvent(event: KeyEvent): Boolean {
+        if (enableOverviewIconMenu()) {
+            return getTaskMenu()?.isOpen == true || event.keyCode == KeyEvent.KEYCODE_TAB
+        }
+        return false
+    }
+
+    fun updateChildTaskOrientations() {
+        with(recentsView) {
+            taskViews.forEach { it.setOrientationState(mOrientationState) }
+            if (enableOverviewIconMenu()) {
+                children.forEach {
+                    it.layoutDirection = if (isRtl) LAYOUT_DIRECTION_LTR else LAYOUT_DIRECTION_RTL
+                }
+            }
+
+            // Return when it's not fake landscape
+            if (mOrientationState.isRecentsActivityRotationAllowed) return@with
+
+            // Rotation is supported on phone (details at b/254198019#comment4)
+            getTaskMenu()?.onRotationChanged()
+        }
+    }
+
     var deskExplodeProgress: Float = 0f
         set(value) {
             field = value
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index ec6d1c4..afe7e92 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -21,6 +21,7 @@
 import android.util.Log
 import android.view.View
 import android.view.View.OnClickListener
+import com.android.app.tracing.traceSection
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.model.data.TaskViewItemInfo
 import com.android.launcher3.util.SplitConfigurationOptions
@@ -100,26 +101,28 @@
     val itemInfo: TaskViewItemInfo
         get() = TaskViewItemInfo(taskView, this)
 
-    fun bind() {
-        digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
-        if (!enableRefactorTaskThumbnail()) {
-            thumbnailViewDeprecated.bind(task, overlay, taskView)
+    fun bind() =
+        traceSection("TaskContainer.bind") {
+            digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
+            if (!enableRefactorTaskThumbnail()) {
+                thumbnailViewDeprecated.bind(task, overlay, taskView)
+            }
         }
-    }
 
-    fun destroy() {
-        digitalWellBeingToast?.destroy()
-        taskContentView.scaleX = 1f
-        taskContentView.scaleY = 1f
-        overlay.reset()
-        if (enableRefactorTaskThumbnail()) {
-            isThumbnailValid = false
-            thumbnailData = null
-            thumbnailView.onRecycle()
-        } else {
-            thumbnailViewDeprecated.setShowSplashForSplitSelection(false)
+    fun destroy() =
+        traceSection("TaskContainer.destroy") {
+            digitalWellBeingToast?.destroy()
+            taskContentView.scaleX = 1f
+            taskContentView.scaleY = 1f
+            overlay.reset()
+            if (enableRefactorTaskThumbnail()) {
+                isThumbnailValid = false
+                thumbnailData = null
+                thumbnailView.onRecycle()
+            } else {
+                thumbnailViewDeprecated.setShowSplashForSplitSelection(false)
+            }
         }
-    }
 
     fun setOverlayEnabled(enabled: Boolean) {
         if (!enableRefactorTaskThumbnail()) {
@@ -137,23 +140,24 @@
         }
     }
 
-    fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) {
-        this.thumbnailPosition = thumbnailPosition
-        when {
-            !overlayEnabledStatus -> overlay.reset()
-            thumbnailPosition == null -> {
-                Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception())
-                overlay.reset()
+    fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) =
+        traceSection("TaskContainer.refreshOverlay") {
+            this.thumbnailPosition = thumbnailPosition
+            when {
+                !overlayEnabledStatus -> overlay.reset()
+                thumbnailPosition == null -> {
+                    Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception())
+                    overlay.reset()
+                }
+                else ->
+                    overlay.initOverlay(
+                        task,
+                        thumbnailData?.thumbnail,
+                        thumbnailPosition.matrix,
+                        thumbnailPosition.isRotated,
+                    )
             }
-            else ->
-                overlay.initOverlay(
-                    task,
-                    thumbnailData?.thumbnail,
-                    thumbnailPosition.matrix,
-                    thumbnailPosition.isRotated,
-                )
         }
-    }
 
     fun addChildForAccessibility(outChildren: ArrayList<View>) {
         addAccessibleChildToList(iconView.asView(), outChildren)
@@ -168,15 +172,16 @@
         liveTile: Boolean,
         hasHeader: Boolean,
         clickCloseListener: OnClickListener?,
-    ) {
-        taskContentView.setState(
-            TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener),
-            TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile),
-            state?.taskId,
-        )
-        thumbnailData = if (state is TaskData.Data) state.thumbnailData else null
-        overlay.setThumbnailState(thumbnailData)
-    }
+    ) =
+        traceSection("TaskContainer.setState") {
+            taskContentView.setState(
+                TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener),
+                TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile),
+                state?.taskId,
+            )
+            thumbnailData = if (state is TaskData.Data) state.thumbnailData else null
+            overlay.setThumbnailState(thumbnailData)
+        }
 
     fun updateTintAmount(tintAmount: Float) {
         thumbnailView.updateTintAmount(tintAmount)
diff --git a/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt b/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt
index 0427402..1fda5a3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt
@@ -18,16 +18,16 @@
 
 import android.content.Context
 import android.util.AttributeSet
-import android.widget.FrameLayout
 import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.isGone
 import com.android.launcher3.R
 import com.android.quickstep.task.thumbnail.TaskHeaderUiState
 
 class TaskHeaderView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
-    FrameLayout(context, attrs) {
+    ConstraintLayout(context, attrs) {
 
     private val headerTitleView: TextView by lazy { findViewById(R.id.header_app_title) }
     private val headerIconView: ImageView by lazy { findViewById(R.id.header_app_icon) }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.kt b/quickstep/src/com/android/quickstep/views/TaskMenuView.kt
index 7c762f4..696f934 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.kt
@@ -22,11 +22,11 @@
 import android.content.Context
 import android.graphics.Outline
 import android.graphics.Rect
-import android.graphics.drawable.GradientDrawable
 import android.graphics.drawable.ShapeDrawable
 import android.graphics.drawable.shapes.RectShape
 import android.util.AttributeSet
 import android.view.Gravity
+import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewOutlineProvider
@@ -165,7 +165,18 @@
             recentsViewContainer.layoutInflater.inflate(R.layout.task_view_menu_option, this, false)
                 as LinearLayout
         if (enableOverviewIconMenu()) {
-            (menuOptionView.background as GradientDrawable).cornerRadius = 0f
+            menuOptionView.background =
+                ResourcesCompat.getDrawable(
+                    resources,
+                    R.drawable.app_chip_menu_item_bg,
+                    context.theme,
+                )
+            menuOptionView.foreground =
+                ResourcesCompat.getDrawable(
+                    resources,
+                    R.drawable.app_chip_menu_item_fg,
+                    context.theme,
+                )
         }
         menuOption.setIconAndLabelFor(
             menuOptionView.findViewById(R.id.icon),
@@ -366,13 +377,10 @@
             deviceProfile = recentsViewContainer.deviceProfile,
             taskMenuX = translationX,
             taskMenuY =
-                when {
-                    !enableOverviewIconMenu() -> translationY
-                    // Bottom menu can translate up to show more options. So we use the min
-                    // translation allowed to calculate its max height.
-                    taskView.isOnGridBottomRow() -> minMenuTop
-                    else -> menuTranslationYBeforeOpen
-                },
+                // Bottom menu can translate up to show more options. So we use the min
+                // translation allowed to calculate its max height.
+                if (enableOverviewIconMenu() && taskView.isOnGridBottomRow()) minMenuTop
+                else translationY,
         )
 
     private fun setOnClosingStartCallback(onClosingStartCallback: Runnable?) {
@@ -458,6 +466,24 @@
         animatorBuilder.with(menuTranslationXAnim)
     }
 
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (enableOverviewIconMenu()) {
+            if (event.action != KeyEvent.ACTION_DOWN) return super.dispatchKeyEvent(event)
+
+            val isFirstMenuOptionFocused = optionLayout.indexOfChild(optionLayout.focusedChild) == 0
+            val isLastMenuOptionFocused =
+                optionLayout.indexOfChild(optionLayout.focusedChild) == optionLayout.childCount - 1
+            if (
+                (isLastMenuOptionFocused && event.keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
+                || (isFirstMenuOptionFocused && event.keyCode == KeyEvent.KEYCODE_DPAD_UP)
+            ) {
+                iconView.requestFocus()
+                return true
+            }
+        }
+        return super.dispatchKeyEvent(event)
+    }
+
     companion object {
         private val REVEAL_OPEN_DURATION = if (enableOverviewIconMenu()) 417L else 150L
         private val REVEAL_CLOSE_DURATION = if (enableOverviewIconMenu()) 333L else 100L
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 55432b8..3d1643c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -42,6 +42,8 @@
 import androidx.annotation.VisibleForTesting
 import androidx.core.view.updateLayoutParams
 import com.android.app.animation.Interpolators
+import com.android.app.tracing.traceSection
+import com.android.launcher3.AbstractFloatingView
 import com.android.launcher3.Flags.enableCursorHoverStates
 import com.android.launcher3.Flags.enableDesktopExplodedView
 import com.android.launcher3.Flags.enableGridOnlyOverview
@@ -75,6 +77,7 @@
 import com.android.quickstep.FullscreenDrawParams
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.RemoteAnimationTargets
+import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.TaskViewUtils
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler
@@ -141,11 +144,10 @@
         /** Returns whether the task is part of overview grid and not being focused. */
         get() = container.deviceProfile.isTablet && !isLargeTile
 
-    // TODO: b/400532675 - This will not work for empty desks until b/400532675 is fixed.
     val isRunningTask: Boolean
         get() = this === recentsView?.runningTaskView
 
-    val displayId: Int
+    open val displayId: Int
         get() = taskContainers.firstOrNull()?.task.displayId
 
     val isExternalDisplay: Boolean
@@ -614,6 +616,16 @@
         super.draw(canvas)
     }
 
+    override fun setLayoutDirection(layoutDirection: Int) {
+        super.setLayoutDirection(layoutDirection)
+        if (enableOverviewIconMenu()) {
+            val deviceLayoutDirection = resources.configuration.layoutDirection
+            taskContainers.forEach {
+                (it.iconView as IconAppChipView).layoutDirection = deviceLayoutDirection
+            }
+        }
+    }
+
     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
         super.onLayout(changed, left, top, right, bottom)
         val thumbnailTopMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
@@ -734,61 +746,63 @@
             ?.inflate()
     }
 
-    override fun onAttachedToWindow() {
-        super.onAttachedToWindow()
-        if (enableRefactorTaskThumbnail()) {
-            // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in
-            // onRecycle. So it should be initialized at this point. TaskView Lifecycle:
-            // `bind` -> `onBind` ->  onAttachedToWindow() -> onDetachFromWindow -> onRecycle
-            coroutineJobs +=
-                coroutineScope.launch(dispatcherProvider.main) {
-                    viewModel!!.state.collectLatest(::updateTaskViewState)
-                }
-        }
-    }
-
-    private fun updateTaskViewState(state: TaskTileUiState) {
-        sysUiStatusNavFlags = state.sysUiStatusNavFlags
-
-        // Updating containers
-        val mapOfTasks = state.tasks.associateBy { it.taskId }
-        taskContainers.forEach { container ->
-            val taskId = container.task.key.id
-            val containerState = mapOfTasks[taskId]
-            val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView()
-            container.setState(
-                state = containerState,
-                liveTile = state.isLiveTile,
-                hasHeader = shouldHaveHeader,
-                clickCloseListener =
-                    if (shouldHaveHeader) {
-                        {
-                            // Update the layout UI to remove this task from the layout grid, and
-                            // remove the task from ActivityManager afterwards.
-                            recentsView?.dismissTask(
-                                taskId,
-                                /* animate= */ true,
-                                /* removeTask= */ true,
-                            )
-                        }
-                    } else {
-                        null
-                    },
-            )
-            updateThumbnailValidity(container)
-            val thumbnailPosition =
-                updateThumbnailMatrix(
-                    container = container,
-                    width = container.thumbnailView.width,
-                    height = container.thumbnailView.height,
-                )
-            container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition)
-
-            if (enableOverviewIconMenu()) {
-                setIconState(container, containerState)
+    override fun onAttachedToWindow() =
+        traceSection("TaskView.onAttachedToWindow") {
+            super.onAttachedToWindow()
+            if (enableRefactorTaskThumbnail()) {
+                // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in
+                // onRecycle. So it should be initialized at this point. TaskView Lifecycle:
+                // `bind` -> `onBind` ->  onAttachedToWindow() -> onDetachFromWindow -> onRecycle
+                coroutineJobs +=
+                    coroutineScope.launch(dispatcherProvider.main) {
+                        viewModel!!.state.collectLatest(::updateTaskViewState)
+                    }
             }
         }
-    }
+
+    private fun updateTaskViewState(state: TaskTileUiState) =
+        traceSection("TaskView.updateTaskViewState") {
+            sysUiStatusNavFlags = state.sysUiStatusNavFlags
+
+            // Updating containers
+            val mapOfTasks = state.tasks.associateBy { it.taskId }
+            taskContainers.forEach { container ->
+                val taskId = container.task.key.id
+                val containerState = mapOfTasks[taskId]
+                val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView()
+                container.setState(
+                    state = containerState,
+                    liveTile = state.isLiveTile,
+                    hasHeader = shouldHaveHeader,
+                    clickCloseListener =
+                        if (shouldHaveHeader) {
+                            {
+                                // Update the layout UI to remove this task from the layout grid,
+                                // and remove the task from ActivityManager afterwards.
+                                recentsView?.dismissTask(
+                                    taskId,
+                                    /* animate= */ true,
+                                    /* removeTask= */ true,
+                                )
+                            }
+                        } else {
+                            null
+                        },
+                )
+                updateThumbnailValidity(container)
+                val thumbnailPosition =
+                    updateThumbnailMatrix(
+                        container = container,
+                        width = container.thumbnailView.width,
+                        height = container.thumbnailView.height,
+                    )
+                container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition)
+
+                if (enableOverviewIconMenu()) {
+                    setIconState(container, containerState)
+                }
+            }
+        }
 
     private fun updateThumbnailValidity(container: TaskContainer) {
         container.isThumbnailValid =
@@ -815,27 +829,33 @@
         container: TaskContainer,
         width: Int,
         height: Int,
-    ): ThumbnailPosition? {
-        val thumbnailPosition =
-            viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl)
-                ?: return null
-        container.updateThumbnailMatrix(thumbnailPosition.matrix)
-        return thumbnailPosition
-    }
+    ): ThumbnailPosition? =
+        traceSection("TaskView.updateThumbnailMatrix") {
+            val thumbnailPosition =
+                viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl)
+                    ?: return null
+            container.updateThumbnailMatrix(thumbnailPosition.matrix)
+            return thumbnailPosition
+        }
 
-    override fun onDetachedFromWindow() {
-        super.onDetachedFromWindow()
-        if (enableRefactorTaskThumbnail()) {
-            // The jobs are being cancelled in the background thread. So we make a copy of the list
-            // to prevent cleaning a new job that might be added to this list during onAttach
-            // or another moment in the lifecycle.
-            val coroutineJobsToCancel = coroutineJobs.toList()
-            coroutineJobs.clear()
-            coroutineScope.launch(dispatcherProvider.background) {
-                coroutineJobsToCancel.forEach { it.cancel("TaskView detaching from window") }
+    override fun onDetachedFromWindow() =
+        traceSection("TaskView.onDetachedFromWindow") {
+            super.onDetachedFromWindow()
+            if (enableRefactorTaskThumbnail()) {
+                // The jobs are being cancelled in the background thread. So we make a copy of the
+                // list to prevent cleaning a new job that might be added to this list during
+                // onAttach or another moment in the lifecycle.
+                val coroutineJobsToCancel = coroutineJobs.toList()
+                coroutineJobs.clear()
+                coroutineScope.launch(dispatcherProvider.background) {
+                    traceSection("TaskView.onDetachedFromWindow.cancellingJobs") {
+                        coroutineJobsToCancel.forEach {
+                            it.cancel("TaskView detaching from window")
+                        }
+                    }
+                }
             }
         }
-    }
 
     /** Updates this task view to the given {@param task}. */
     open fun bind(
@@ -861,37 +881,40 @@
         onBind(orientedState)
     }
 
-    protected open fun onBind(orientedState: RecentsOrientedState) {
-        if (enableRefactorTaskThumbnail()) {
-            val scopeId = context
-            Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}")
-            viewModel =
-                TaskViewModel(
-                        taskViewType = type,
-                        recentsViewData = RecentsDependencies.get(scopeId),
-                        getTaskUseCase = RecentsDependencies.get(scopeId),
-                        getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId),
-                        isThumbnailValidUseCase = RecentsDependencies.get(scopeId),
-                        getThumbnailPositionUseCase = RecentsDependencies.get(scopeId),
-                        dispatcherProvider = RecentsDependencies.get(scopeId),
-                    )
-                    .apply { bind(*taskIds) }
-        }
-
-        taskContainers.forEach { container ->
-            container.bind()
-            if (enableRefactorTaskThumbnail()) {
-                container.taskContentView.cornerRadius =
-                    thumbnailFullscreenParams.currentCornerRadius
-                container.taskContentView.doOnSizeChange { width, height ->
-                    updateThumbnailValidity(container)
-                    val thumbnailPosition = updateThumbnailMatrix(container, width, height)
-                    container.refreshOverlay(thumbnailPosition)
+    protected open fun onBind(orientedState: RecentsOrientedState) =
+        traceSection("TaskView.onBind") {
+            traceSection("TaskView.onBind.createViewModel") {
+                if (enableRefactorTaskThumbnail()) {
+                    val scopeId = context
+                    Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}")
+                    viewModel =
+                        TaskViewModel(
+                                taskViewType = type,
+                                recentsViewData = RecentsDependencies.get(scopeId),
+                                getTaskUseCase = RecentsDependencies.get(scopeId),
+                                getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId),
+                                isThumbnailValidUseCase = RecentsDependencies.get(scopeId),
+                                getThumbnailPositionUseCase = RecentsDependencies.get(scopeId),
+                                dispatcherProvider = RecentsDependencies.get(scopeId),
+                            )
+                            .apply { bind(*taskIds) }
                 }
             }
+
+            taskContainers.forEach { container ->
+                container.bind()
+                if (enableRefactorTaskThumbnail()) {
+                    container.taskContentView.cornerRadius =
+                        thumbnailFullscreenParams.currentCornerRadius
+                    container.taskContentView.doOnSizeChange { width, height ->
+                        updateThumbnailValidity(container)
+                        val thumbnailPosition = updateThumbnailMatrix(container, width, height)
+                        container.refreshOverlay(thumbnailPosition)
+                    }
+                }
+            }
+            setOrientationState(orientedState)
         }
-        setOrientationState(orientedState)
-    }
 
     private fun applyThumbnailSplashAlpha() {
         val alpha = getSplashAlphaProgress()
@@ -917,22 +940,23 @@
         @IdRes digitalWellbeingBannerId: Int,
         @StagePosition stagePosition: Int,
         taskOverlayFactory: TaskOverlayFactory,
-    ): TaskContainer {
-        val iconView = findViewById<View>(iconViewId) as TaskViewIcon
-        val taskContentView = findViewById<TaskContentView>(taskContentViewId)
-        return TaskContainer(
-            this,
-            task,
-            taskContentView,
-            taskContentView.findViewById(thumbnailViewId),
-            iconView,
-            TransformingTouchDelegate(iconView.asView()),
-            stagePosition,
-            findViewById(digitalWellbeingBannerId)!!,
-            findViewById(showWindowViewId)!!,
-            taskOverlayFactory,
-        )
-    }
+    ): TaskContainer =
+        traceSection("TaskView.createTaskContainer") {
+            val iconView = findViewById<View>(iconViewId) as TaskViewIcon
+            val taskContentView = findViewById<TaskContentView>(taskContentViewId)
+            return TaskContainer(
+                this,
+                task,
+                taskContentView,
+                taskContentView.findViewById(thumbnailViewId),
+                iconView,
+                TransformingTouchDelegate(iconView.asView()),
+                stagePosition,
+                findViewById(digitalWellbeingBannerId)!!,
+                findViewById(showWindowViewId)!!,
+                taskOverlayFactory,
+            )
+        }
 
     fun containsMultipleTasks() = taskContainers.size > 1
 
@@ -945,11 +969,12 @@
     /** Check if given `taskId` is tracked in this view */
     fun containsTaskId(taskId: Int) = getTaskContainerById(taskId) != null
 
-    open fun setOrientationState(orientationState: RecentsOrientedState) {
-        this.orientedState = orientationState
-        taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) }
-        setThumbnailOrientation(orientationState)
-    }
+    open fun setOrientationState(orientationState: RecentsOrientedState) =
+        traceSection("TaskView.setOrientationState") {
+            this.orientedState = orientationState
+            taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) }
+            setThumbnailOrientation(orientationState)
+        }
 
     protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) {
         taskContainers.forEach {
@@ -1096,25 +1121,27 @@
     protected open fun needsUpdate(@TaskDataChanges dataChange: Int, @TaskDataChanges flag: Int) =
         (dataChange and flag) == flag
 
-    protected open fun cancelPendingLoadTasks() {
-        pendingThumbnailLoadRequests.forEach { it.cancel() }
-        pendingThumbnailLoadRequests.clear()
-        pendingIconLoadRequests.forEach { it.cancel() }
-        pendingIconLoadRequests.clear()
-    }
+    protected open fun cancelPendingLoadTasks() =
+        traceSection("TaskView.cancelPendingLoadTasks") {
+            pendingThumbnailLoadRequests.forEach { it.cancel() }
+            pendingThumbnailLoadRequests.clear()
+            pendingIconLoadRequests.forEach { it.cancel() }
+            pendingIconLoadRequests.clear()
+        }
 
-    protected open fun setIconState(container: TaskContainer, state: TaskData?) {
-        if (enableOverviewIconMenu()) {
-            if (state is TaskData.Data) {
-                setIcon(container.iconView, state.icon)
-                container.iconView.setText(state.title)
-                container.digitalWellBeingToast?.initialize()
-            } else {
-                setIcon(container.iconView, null)
-                container.iconView.setText(null)
+    protected open fun setIconState(container: TaskContainer, state: TaskData?) =
+        traceSection("TaskView.setIconState") {
+            if (enableOverviewIconMenu()) {
+                if (state is TaskData.Data) {
+                    setIcon(container.iconView, state.icon)
+                    container.iconView.setText(state.title)
+                    container.digitalWellBeingToast?.initialize()
+                } else {
+                    setIcon(container.iconView, null)
+                    container.iconView.setText(null)
+                }
             }
         }
-    }
 
     protected open fun onIconLoaded(taskContainer: TaskContainer) {
         setIcon(taskContainer.iconView, taskContainer.task.icon)
@@ -1194,15 +1221,14 @@
     /** Launch of the current task (both live and inactive tasks) with an animation. */
     fun launchWithAnimation(): RunnableList? {
         return if (isRunningTask && recentsView?.remoteTargetHandles != null) {
-            launchAsLiveTile()
+            launchAsLiveTile(recentsView?.remoteTargetHandles!!)
         } else {
             launchAsStaticTile()
         }
     }
 
-    private fun launchAsLiveTile(): RunnableList? {
+    private fun launchAsLiveTile(remoteTargetHandles: Array<RemoteTargetHandle>): RunnableList? {
         val recentsView = recentsView ?: return null
-        val remoteTargetHandles = recentsView.remoteTargetHandles
         if (!isClickableAsLiveTile) {
             Log.e(
                 TAG,
@@ -1212,21 +1238,27 @@
         }
         isClickableAsLiveTile = false
         val targets =
-            if (remoteTargetHandles.size == 1) {
-                remoteTargetHandles[0].transformParams.targetSet
+            if (remoteTargetHandles.isNotEmpty()) {
+                if (remoteTargetHandles.size == 1) {
+                    remoteTargetHandles[0].transformParams.targetSet
+                } else {
+                    val apps =
+                        remoteTargetHandles.flatMap {
+                            it.transformParams.targetSet.apps.asIterable()
+                        }
+                    val wallpapers =
+                        remoteTargetHandles.flatMap {
+                            it.transformParams.targetSet.wallpapers.asIterable()
+                        }
+                    RemoteAnimationTargets(
+                        apps.toTypedArray(),
+                        wallpapers.toTypedArray(),
+                        remoteTargetHandles[0].transformParams.targetSet.nonApps,
+                        remoteTargetHandles[0].transformParams.targetSet.targetMode,
+                    )
+                }
             } else {
-                val apps =
-                    remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() }
-                val wallpapers =
-                    remoteTargetHandles.flatMap {
-                        it.transformParams.targetSet.wallpapers.asIterable()
-                    }
-                RemoteAnimationTargets(
-                    apps.toTypedArray(),
-                    wallpapers.toTypedArray(),
-                    remoteTargetHandles[0].transformParams.targetSet.nonApps,
-                    remoteTargetHandles[0].transformParams.targetSet.targetMode,
-                )
+                null
             }
         if (targets == null) {
             // If the recents animation is cancelled somehow between the parent if block and
@@ -1467,6 +1499,20 @@
         return showTaskMenuWithContainer(menuContainer)
     }
 
+    private fun closeTaskMenu(): Boolean {
+        val floatingView: AbstractFloatingView? =
+            AbstractFloatingView.getTopOpenViewWithType(
+                container,
+                AbstractFloatingView.TYPE_TASK_MENU,
+            )
+        if (floatingView?.isOpen == true) {
+            floatingView.close(true)
+            return true
+        } else {
+            return false
+        }
+    }
+
     private fun showTaskMenuWithContainer(menuContainer: TaskContainer): Boolean {
         val recentsView = recentsView ?: return false
         if (enableHoverOfChildElementsInTaskview()) {
@@ -1474,12 +1520,16 @@
             recentsView.setTaskBorderEnabled(false)
         }
         return if (enableOverviewIconMenu() && menuContainer.iconView is IconAppChipView) {
-            menuContainer.iconView.revealAnim(/* isRevealing= */ true)
-            TaskMenuView.showForTask(menuContainer) {
-                val isAnimated = !recentsView.isSplitSelectionActive
-                menuContainer.iconView.revealAnim(/* isRevealing= */ false, isAnimated)
-                if (enableHoverOfChildElementsInTaskview()) {
-                    recentsView.setTaskBorderEnabled(true)
+            if (menuContainer.iconView.isExpanded) {
+                closeTaskMenu()
+            } else {
+                menuContainer.iconView.revealAnim(/* isRevealing= */ true)
+                TaskMenuView.showForTask(menuContainer) {
+                    val isAnimated = !recentsView.isSplitSelectionActive
+                    menuContainer.iconView.revealAnim(/* isRevealing= */ false, isAnimated)
+                    if (enableHoverOfChildElementsInTaskview()) {
+                        recentsView.setTaskBorderEnabled(true)
+                    }
                 }
             }
         } else if (container.deviceProfile.isTablet) {
diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
index 18a5338..773a039 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
@@ -551,4 +551,13 @@
                 displayRotation, displaySize.flattenToString(), swipeRegion.toShortString(),
                 ohmRegion.toShortString(), gesturalHeight, largerGesturalHeight, reason);
     }
+
+    public static void logOnTaskAnimationManagerNotAvailable(int displayId) {
+        ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                "TaskAnimationManager not available for displayId=%d",
+                displayId));
+        if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
+        ProtoLog.d(ACTIVE_GESTURE_LOG, "TaskAnimationManager not available for displayId=%d",
+                displayId);
+    }
 }
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt
index d36faa2..7b1e445 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt
@@ -18,11 +18,15 @@
 import android.content.Context
 import android.graphics.Color
 import android.graphics.drawable.BitmapDrawable
+import android.platform.test.flag.junit.SetFlagsRule
 import android.view.LayoutInflater
+import com.android.launcher3.Flags
 import com.android.launcher3.R
+import com.android.launcher3.util.rule.setFlags
 import com.android.quickstep.task.thumbnail.SplashHelper.createSplash
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
 import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -37,13 +41,20 @@
 @RunWith(ParameterizedAndroidJunit4::class)
 class TaskContentViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
 
-    @get:Rule
+    @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+
+    @get:Rule(order = 1)
     val screenshotRule =
         ViewScreenshotTestRule(
             emulationSpec,
             ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)),
         )
 
+    @Before
+    fun setUp() {
+        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL)
+    }
+
     @Test
     fun taskContentView_recyclesToUninitialized() {
         screenshotRule.screenshotTest("taskContentView_uninitialized") { activity ->
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
index 09c62aa..1c7af14 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
@@ -64,7 +64,7 @@
         underTest.mHotseatState.predictor = hotseatPredictor
         underTest.mWidgetsRecommendationState.predictor = widgetRecommendationPredictor
         underTest.mModel = modelHelper.model
-        underTest.mDataModel = BgDataModel()
+        underTest.mDataModel = BgDataModel(WidgetsModel(modelHelper.sandboxContext))
     }
 
     @After
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 26f1197..52d288a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -17,6 +17,7 @@
 
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController
 import com.android.launcher3.taskbar.bubbles.BubbleControllers
+import com.android.launcher3.taskbar.growth.NudgeController
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
 import com.android.systemui.shared.rotation.RotationButtonController
 import java.util.Optional
@@ -58,6 +59,7 @@
     @Mock lateinit var taskbarPinningController: TaskbarPinningController
     @Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers>
     @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
+    @Mock lateinit var nudgeController: NudgeController
 
     lateinit var taskbarControllers: TaskbarControllers
 
@@ -100,6 +102,7 @@
                 taskbarPinningController,
                 optionalBubbleControllers,
                 taskbarDesktopModeController,
+                nudgeController,
             )
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index 3761044..c589415 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Display.DEFAULT_DISPLAY
 import androidx.test.core.app.ApplicationProvider
 import com.android.launcher3.Flags.FLAG_ENABLE_MULTI_INSTANCE_MENU_TASKBAR
 import com.android.launcher3.Flags.FLAG_TASKBAR_OVERFLOW
@@ -446,7 +447,7 @@
                 )
             })
 
-        recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, tasks)))
+        recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, DEFAULT_DISPLAY, tasks)))
         for (task in 1..tasks.size) {
             desktopTaskListener?.onTasksVisibilityChanged(
                 context.virtualDisplay.display.displayId,
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 8376bc1..8758d7c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -25,6 +25,7 @@
 import android.os.Process
 import android.os.UserHandle
 import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
 import androidx.test.annotation.UiThreadTest
 import com.android.internal.R
 import com.android.launcher3.BubbleTextView.RunningAppState
@@ -877,7 +878,7 @@
         val allTasks =
             ArrayList<GroupTask>().apply {
                 if (!runningTasks.isEmpty()) {
-                    add(DesktopTask(deskId = 0, ArrayList(runningTasks)))
+                    add(DesktopTask(deskId = 0, DEFAULT_DISPLAY, ArrayList(runningTasks)))
                 }
                 addAll(recentTasks)
             }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 6fbbd59..7824000 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -49,6 +49,7 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.Display;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.ViewTreeObserver;
@@ -189,7 +190,7 @@
     @Before
     public void setUpRecentsContainer() {
         mTaskAnimationManager = new TaskAnimationManager(mContext,
-                RecentsAnimationDeviceState.INSTANCE.get(mContext));
+                RecentsAnimationDeviceState.INSTANCE.get(mContext), Display.DEFAULT_DISPLAY);
         RecentsViewContainer recentsContainer = getRecentsContainer();
         RECENTS_VIEW recentsView = getRecentsView();
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
index 56c01f9..381ac68 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
@@ -67,7 +67,6 @@
                 OverviewCommandHelper(
                     touchInteractionService = mock(),
                     overviewComponentObserver = mock(),
-                    taskAnimationManager = mock(),
                     dispatcherProvider = TestDispatcherProvider(dispatcher),
                     recentsDisplayModel = mock(),
                     focusState = mock(),
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
index 9722e9d..1e4315a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
@@ -52,6 +52,7 @@
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.DaggerSingletonTracker;
 import com.android.launcher3.util.LooperExecutor;
+import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.TaskViewType;
 import com.android.systemui.shared.recents.model.Task;
@@ -148,6 +149,66 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    public void loadTasksInBackground_freeformTask_multiDesksInMultiDisplays() throws Exception {
+        List<TaskInfo> tasksInDefaultDesk1 = Arrays.asList(
+                createRecentTaskInfo(/* taskId = */ 1, DEFAULT_DISPLAY),
+                createRecentTaskInfo(/* taskId = */ 4, DEFAULT_DISPLAY));
+        List<TaskInfo> tasksInDefaultDesk2 = Arrays.asList(
+                createRecentTaskInfo(/* taskId = */ 2, DEFAULT_DISPLAY),
+                createRecentTaskInfo(/* taskId = */ 3, DEFAULT_DISPLAY));
+        List<TaskInfo> tasksInExtend = Arrays.asList(
+                createRecentTaskInfo(/* taskId = */ 5, /* displayId = */ 1),
+                createRecentTaskInfo(/* taskId = */ 6, /* displayId = */ 1));
+        GroupedTaskInfo recentTaskInfosOfDesk1 = GroupedTaskInfo.forDeskTasks(/* deskId = */1,
+                DEFAULT_DISPLAY, tasksInDefaultDesk1, /* minimizedTaskIds = */
+                Collections.emptySet());
+        GroupedTaskInfo recentTaskInfosOfDesk2 = GroupedTaskInfo.forDeskTasks(/* deskId = */2,
+                DEFAULT_DISPLAY, tasksInDefaultDesk2, /* minimizedTaskIds = */
+                Collections.emptySet());
+        GroupedTaskInfo recentTaskInfosOfDesk3 = GroupedTaskInfo.forDeskTasks(/* deskId = */3,
+                /* displayId = */ 1, tasksInExtend, /* minimizedTaskIds = */
+                Collections.emptySet());
+        when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt())).thenReturn(
+                new ArrayList<>(Arrays.asList(recentTaskInfosOfDesk1, recentTaskInfosOfDesk2,
+                        recentTaskInfosOfDesk3)));
+
+        List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
+                false);
+
+        assertThat(taskList).hasSize(3);
+        assertThat(taskList.get(2).taskViewType).isEqualTo(TaskViewType.DESKTOP);
+        List<Task> actualFreeformTasksInDesk1 = taskList.get(2).getTasks();
+        assertThat(actualFreeformTasksInDesk1).hasSize(2);
+        assertThat(actualFreeformTasksInDesk1.get(0).key.id).isEqualTo(1);
+        assertThat(actualFreeformTasksInDesk1.get(0).isMinimized).isFalse();
+        assertThat(actualFreeformTasksInDesk1.get(1).key.id).isEqualTo(4);
+        assertThat(actualFreeformTasksInDesk1.get(1).isMinimized).isFalse();
+        assertThat(((DesktopTask) taskList.get(2)).getDeskId()).isEqualTo(1);
+        assertThat(((DesktopTask) taskList.get(2)).getDisplayId()).isEqualTo(DEFAULT_DISPLAY);
+
+        assertThat(taskList.get(1).taskViewType).isEqualTo(TaskViewType.DESKTOP);
+        List<Task> actualFreeformTasksInDesk2 = taskList.get(1).getTasks();
+        assertThat(actualFreeformTasksInDesk2).hasSize(2);
+        assertThat(actualFreeformTasksInDesk2.get(0).key.id).isEqualTo(2);
+        assertThat(actualFreeformTasksInDesk2.get(0).isMinimized).isFalse();
+        assertThat(actualFreeformTasksInDesk2.get(1).key.id).isEqualTo(3);
+        assertThat(actualFreeformTasksInDesk2.get(1).isMinimized).isFalse();
+        assertThat(((DesktopTask) taskList.get(1)).getDeskId()).isEqualTo(2);
+        assertThat(((DesktopTask) taskList.get(1)).getDisplayId()).isEqualTo(DEFAULT_DISPLAY);
+
+        assertThat(taskList.get(0).taskViewType).isEqualTo(TaskViewType.DESKTOP);
+        List<Task> actualFreeformTasksInDesk3 = taskList.get(0).getTasks();
+        assertThat(actualFreeformTasksInDesk3).hasSize(2);
+        assertThat(actualFreeformTasksInDesk3.get(0).key.id).isEqualTo(5);
+        assertThat(actualFreeformTasksInDesk3.get(0).isMinimized).isFalse();
+        assertThat(actualFreeformTasksInDesk3.get(1).key.id).isEqualTo(6);
+        assertThat(actualFreeformTasksInDesk3.get(1).isMinimized).isFalse();
+        assertThat(((DesktopTask) taskList.get(0)).getDeskId()).isEqualTo(3);
+        assertThat(((DesktopTask) taskList.get(0)).getDisplayId()).isEqualTo(1);
+    }
+
+    @Test
     public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() throws Exception  {
         String taskDescription = "Wheeee!";
         RecentTaskInfo task1 = new RecentTaskInfo();
@@ -175,7 +236,8 @@
     }
 
     @Test
-    @DisableFlags(FLAG_ENABLE_SEPARATE_EXTERNAL_DISPLAY_TASKS)
+    @DisableFlags({FLAG_ENABLE_SEPARATE_EXTERNAL_DISPLAY_TASKS,
+            FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND})
     public void loadTasksInBackground_freeformTask_createsDesktopTask() throws Exception  {
         List<TaskInfo> tasks = Arrays.asList(
                 createRecentTaskInfo(1 /* taskId */, DEFAULT_DISPLAY),
@@ -183,7 +245,8 @@
                 createRecentTaskInfo(5 /* taskId */, 1 /* displayId */),
                 createRecentTaskInfo(6 /* taskId */, 1 /* displayId */));
         GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks(
-                0 /* deskId */, tasks, Collections.emptySet() /* minimizedTaskIds */);
+                0 /* deskId */, DEFAULT_DISPLAY, tasks,
+                Collections.emptySet() /* minimizedTaskIds */);
         when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
 
@@ -214,7 +277,8 @@
                 createRecentTaskInfo(5 /* taskId */, 1 /* displayId */),
                 createRecentTaskInfo(6 /* taskId */, 1 /* displayId */));
         GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks(
-                0 /* deskId */, tasks, Collections.emptySet() /* minimizedTaskIds */);
+                0 /* deskId */, DEFAULT_DISPLAY, tasks,
+                Collections.emptySet() /* minimizedTaskIds */);
         when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
 
@@ -248,7 +312,7 @@
         Set<Integer> minimizedTaskIds =
                 Arrays.stream(new Integer[]{1, 4, 5}).collect(Collectors.toSet());
         GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks(
-                0 /* deskId */, tasks, minimizedTaskIds);
+                0 /* deskId */, DEFAULT_DISPLAY, tasks, minimizedTaskIds);
         when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 6e9885a..fd88a5c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -26,6 +26,7 @@
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
+import android.view.Display;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -54,7 +55,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mTaskAnimationManager = new TaskAnimationManager(mContext,
-                RecentsAnimationDeviceState.INSTANCE.get(mContext)) {
+                RecentsAnimationDeviceState.INSTANCE.get(mContext), Display.DEFAULT_DISPLAY) {
             @Override
             SystemUiProxy getSystemUiProxy() {
                 return mSystemUiProxy;
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
index 0570c26..66b3b04 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
@@ -43,12 +43,12 @@
         if (isEnabled) {
             setFlagsRule.enableFlags(
                 Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
-                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU,
             )
         } else {
             setFlagsRule.disableFlags(
                 Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
-                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU,
             )
         }
     }
@@ -108,14 +108,8 @@
 
         val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
 
-        // TODO(b/326377497): When started in fake seascape and rotated to landscape,
-        //  the icon chips are in RTL and wrongly positioned at the right side of the snapshot.
-        //  Top-Left app chip should be placed at the top left of the first snapshot, but because
-        //  this issue, it's displayed at the top-right of the second snapshot.
-        //  The Bottom-Right app chip is displayed at the top-right of the first snapshot because
-        //  of this issue.
-        assertThat(topLeftY).isEqualTo(0)
-        assertThat(bottomRightY).isEqualTo(-316)
+        assertThat(topLeftY).isEqualTo(-316)
+        assertThat(bottomRightY).isEqualTo(0)
     }
 
     /** Test updateSplitIconsPosition */
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
index 3788688..d455b0d 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
@@ -43,12 +43,12 @@
         if (isEnabled) {
             setFlagsRule.enableFlags(
                 Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
-                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU,
             )
         } else {
             setFlagsRule.disableFlags(
                 Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
-                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU,
             )
         }
     }
@@ -110,12 +110,6 @@
 
         val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
 
-        // TODO(b/326377497): When started in fake seascape and rotated to landscape,
-        //  the icon chips are in RTL and wrongly positioned at the right side of the snapshot.
-        //  Top-Left app chip should be placed at the top left of the first snapshot, but because
-        //  this issue, it's displayed at the top-right of the second snapshot.
-        //  The Bottom-Right app chip is displayed at the top-right of the first snapshot because
-        //  of this issue.
         assertThat(topLeftY).isEqualTo(316)
         assertThat(bottomRightY).isEqualTo(0)
     }
@@ -167,7 +161,7 @@
         `when`(iconView.layoutParams).thenReturn(frameLayout)
 
         sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
-        assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.END)
         verify(iconView).setSplitTranslationX(0f)
         verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
     }
@@ -182,7 +176,7 @@
         `when`(iconView.layoutParams).thenReturn(frameLayout)
 
         sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
-        assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.START)
         verify(iconView).setSplitTranslationX(0f)
         verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
     }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index 6790567..e22892c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -21,6 +21,7 @@
 import android.graphics.Bitmap
 import android.graphics.Rect
 import android.graphics.drawable.Drawable
+import android.view.Display.DEFAULT_DISPLAY
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TestDispatcherProvider
@@ -64,7 +65,7 @@
                     /* snapPosition = */ SNAP_TO_2_50_50,
                 ),
             ),
-            DesktopTask(deskId = 0, tasks.subList(3, 6)),
+            DesktopTask(deskId = 0, DEFAULT_DISPLAY, tasks.subList(3, 6)),
         )
     private val recentsModel = FakeRecentTasksDataSource()
     private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt
index b49923f..6c0d0ed 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt
@@ -19,7 +19,9 @@
 import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.drawable.ShapeDrawable
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
 import android.view.Surface
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -31,12 +33,15 @@
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
 import com.android.systemui.shared.recents.model.ThumbnailData
 import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 class TaskUiStateMapperTest {
 
+    @get:Rule val mSetFlagsRule = SetFlagsRule()
+
     /** TaskHeaderUiState */
     @Test
     fun taskData_isNull_returns_HideHeader() {
@@ -49,6 +54,29 @@
         assertThat(result).isEqualTo(TaskHeaderUiState.HideHeader)
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW)
+    @Test
+    fun explodedFlagDisabled_returnsHideHeader() {
+        val inputs =
+            listOf(
+                TASK_DATA,
+                TASK_DATA.copy(thumbnailData = null),
+                TASK_DATA.copy(isLocked = true),
+                TASK_DATA.copy(title = null),
+            )
+        val closeCallback = View.OnClickListener {}
+        val expected = TaskHeaderUiState.HideHeader
+        inputs.forEach { taskData ->
+            val result =
+                TaskUiStateMapper.toTaskHeaderState(
+                    taskData = taskData,
+                    hasHeader = true,
+                    clickCloseListener = closeCallback,
+                )
+            assertThat(result).isEqualTo(expected)
+        }
+    }
+
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW)
     @Test
     fun taskData_hasHeader_and_taskData_returnsShowHeader() {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt
index 6fbf482..15da4d4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName
 import android.content.Intent
+import android.view.Display.DEFAULT_DISPLAY
 import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.android.systemui.shared.recents.model.Task
 import com.google.common.truth.Truth.assertThat
@@ -29,42 +30,42 @@
 
     @Test
     fun testDesktopTask_sameInstance_isEqual() {
-        val task = DesktopTask(deskId = 0, createTasks(1))
+        val task = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
         assertThat(task).isEqualTo(task)
     }
 
     @Test
     fun testDesktopTask_identicalConstructor_isEqual() {
-        val task1 = DesktopTask(deskId = 0, createTasks(1))
-        val task2 = DesktopTask(deskId = 0, createTasks(1))
+        val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
+        val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
         assertThat(task1).isEqualTo(task2)
     }
 
     @Test
     fun testDesktopTask_copy_isEqual() {
-        val task1 = DesktopTask(deskId = 0, createTasks(1))
+        val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
         val task2 = task1.copy()
         assertThat(task1).isEqualTo(task2)
     }
 
     @Test
     fun testDesktopTask_differentDeskIds_isNotEqual() {
-        val task1 = DesktopTask(deskId = 0, createTasks(1))
-        val task2 = DesktopTask(deskId = 1, createTasks(1))
+        val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
+        val task2 = DesktopTask(deskId = 1, DEFAULT_DISPLAY, createTasks(1))
         assertThat(task1).isNotEqualTo(task2)
     }
 
     @Test
     fun testDesktopTask_differentTaskIds_isNotEqual() {
-        val task1 = DesktopTask(deskId = 0, createTasks(1))
-        val task2 = DesktopTask(deskId = 0, createTasks(2))
+        val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
+        val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(2))
         assertThat(task1).isNotEqualTo(task2)
     }
 
     @Test
     fun testDesktopTask_differentLength_isNotEqual() {
-        val task1 = DesktopTask(deskId = 0, createTasks(1))
-        val task2 = DesktopTask(deskId = 0, createTasks(1, 2))
+        val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1))
+        val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1, 2))
         assertThat(task1).isNotEqualTo(task2)
     }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
index 67fc62f..9f49171 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
@@ -19,6 +19,7 @@
 import android.content.ComponentName
 import android.content.Intent
 import android.graphics.Rect
+import android.view.Display.DEFAULT_DISPLAY
 import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.systemui.shared.recents.model.Task
@@ -98,7 +99,7 @@
     @Test
     fun testGroupTask_differentType_isNotEqual() {
         val task1 = SingleTask(createTask(1))
-        val task2 = DesktopTask(deskId = 0, listOf(createTask(1)))
+        val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, listOf(createTask(1)))
         assertThat(task1).isNotEqualTo(task2)
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
index ef6f55e..93b979c 100644
--- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -27,7 +27,6 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Looper;
 import android.view.Choreographer;
 import android.view.Display;
@@ -100,12 +99,13 @@
 
     @Rule public final SandboxApplication mContext = new SandboxApplication();
 
+    private final int mDisplayId = Display.DEFAULT_DISPLAY;
     @NonNull private final InputMonitorCompat mInputMonitorCompat =
-            new InputMonitorCompat("", Display.DEFAULT_DISPLAY);
+            new InputMonitorCompat("", mDisplayId);
 
     private TaskAnimationManager mTaskAnimationManager;
     private InputChannelCompat.InputEventReceiver mInputEventReceiver;
-    @Nullable private ResetGestureInputConsumer mResetGestureInputConsumer;
+    private boolean mUserUnlocked = true;
     @NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null;
 
     @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext;
@@ -126,8 +126,7 @@
 
     @Before
     public void setupTaskAnimationManager() {
-        mTaskAnimationManager = new TaskAnimationManager(
-                mContext, mDeviceState);
+        mTaskAnimationManager = new TaskAnimationManager(mContext, mDeviceState, mDisplayId);
     }
 
     @Before
@@ -164,12 +163,6 @@
     }
 
     @Before
-    public void setUpResetGestureInputConsumer() {
-        mResetGestureInputConsumer = new ResetGestureInputConsumer(
-                mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
-    }
-
-    @Before
     public void setupLockedUserState() {
         when(mLockedUserState.isUserUnlocked()).thenReturn(true);
     }
@@ -314,8 +307,6 @@
 
     @Test
     public void testNewBaseConsumer_containsOtherActivityInputConsumer() {
-        // OtherActivityInputConsumer needs to be initialized on the main thread because of
-        // MotionPauseDetector.mForcePauseTimeout
         assertCorrectInputConsumer(
                 this::createBaseInputConsumer,
                 OtherActivityInputConsumer.class,
@@ -486,7 +477,7 @@
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
         InputConsumer inputConsumer = newConsumer(
                 mContext,
-                mResetGestureInputConsumer,
+                mUserUnlocked,
                 mOverviewComponentObserver,
                 mDeviceState,
                 mPreviousGestureState,
@@ -510,7 +501,8 @@
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
         InputConsumer inputConsumer = newBaseConsumer(
                 mContext,
-                mResetGestureInputConsumer,
+                mUserUnlocked,
+                mTaskbarManager,
                 mOverviewComponentObserver,
                 mDeviceState,
                 mPreviousGestureState,
@@ -535,12 +527,15 @@
                 ResetGestureInputConsumer.class,
                 InputConsumer.TYPE_RESET_GESTURE);
 
-        mResetGestureInputConsumer = null;
+        mUserUnlocked = false;
 
-        runOnMainSync(() -> assertThat(inputConsumerProvider.get()).isEqualTo(InputConsumer.NO_OP));
+        assertCorrectInputConsumer(
+                inputConsumerProvider,
+                InputConsumer.class,
+                InputConsumer.TYPE_NO_OP);
     }
 
-    private static void assertCorrectInputConsumer(
+    private void assertCorrectInputConsumer(
             @NonNull Provider<InputConsumer> inputConsumerProvider,
             @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
             int expectedType) {
@@ -551,11 +546,13 @@
                 expectedType);
     }
 
-    private static void assertCorrectInputConsumer(
+    private void assertCorrectInputConsumer(
             @NonNull Provider<InputConsumer> inputConsumerProvider,
             @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
             @NonNull Class<? extends InputConsumer> expectedActiveConsumer,
             int expectedType) {
+        when(mCurrentGestureState.getDisplayId()).thenReturn(mDisplayId);
+
         runOnMainSync(() -> {
             InputConsumer inputConsumer = inputConsumerProvider.get();
 
@@ -563,7 +560,14 @@
             assertThat(inputConsumer.getActiveConsumerInHierarchy())
                     .isInstanceOf(expectedActiveConsumer);
             assertThat(inputConsumer.getType()).isEqualTo(expectedType);
+            assertThat(inputConsumer.getDisplayId()).isEqualTo(mDisplayId);
         });
+        int expectedDisplayId = mDisplayId + 1;
+
+        when(mCurrentGestureState.getDisplayId()).thenReturn(expectedDisplayId);
+
+        runOnMainSync(() -> assertThat(inputConsumerProvider.get().getDisplayId())
+                .isEqualTo(expectedDisplayId));
     }
 
     private static void runOnMainSync(@NonNull Runnable runnable) {
diff --git a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt b/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt
index 47108e0..daa77d2 100644
--- a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt
@@ -32,7 +32,9 @@
 import android.view.SurfaceControl
 import android.view.WindowManager
 import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
 import androidx.core.util.Supplier
+import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
 import com.android.app.animation.Interpolators
 import com.android.internal.jank.Cuj
 import com.android.launcher3.desktop.DesktopAppLaunchAnimatorHelper
@@ -45,6 +47,7 @@
 import org.junit.Test
 import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
 class DesktopAppLaunchAnimatorHelperTest {
@@ -70,6 +73,10 @@
         whenever(transactionSupplier.get()).thenReturn(transaction)
         whenever(transaction.setCrop(any(), any())).thenReturn(transaction)
         whenever(transaction.setCornerRadius(any(), any())).thenReturn(transaction)
+        whenever(transaction.setScale(any(), any(), any())).thenReturn(transaction)
+        whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction)
+        whenever(transaction.setAlpha(any(), any())).thenReturn(transaction)
+        whenever(transaction.setFrameTimeline(any())).thenReturn(transaction)
 
         whenever(context.resources).thenReturn(resources)
         whenever(resources.displayMetrics).thenReturn(DisplayMetrics())
@@ -77,14 +84,8 @@
     }
 
     @Test
-    fun launchTransition_returnsLaunchAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
+    fun launchTransition_returnsLaunchAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -93,14 +94,27 @@
     }
 
     @Test
-    fun noLaunchTransition_returnsEmptyAnimatorsList() {
+    fun launchTransition_callsAnimationEndListener() = runOnUiThread {
+        val finishCallback = mock<Function1<Animator, Unit>>()
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE))
+
+        val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback)
+
+        animators.forEach { animator ->
+            animator.start()
+            animator.end()
+            verify(finishCallback).invoke(animator)
+        }
+    }
+
+    @Test
+    fun noLaunchTransition_returnsEmptyAnimatorsList() = runOnUiThread {
         val pipChange =
             TransitionInfo.Change(mock(), mock()).apply {
                 mode = WindowManager.TRANSIT_PIP
                 taskInfo = TASK_INFO_FREEFORM
             }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(pipChange)
+        val transitionInfo = createTransitionInfo(listOf(pipChange))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -108,20 +122,8 @@
     }
 
     @Test
-    fun minimizeTransition_returnsLaunchAndMinimizeAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val minimizeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_TO_BACK
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
-        transitionInfo.addChange(minimizeChange)
+    fun minimizeTransition_returnsLaunchAndMinimizeAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, MINIMIZE_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -131,21 +133,23 @@
     }
 
     @Test
+    fun minimizeTransition_callsAnimationEndListener() = runOnUiThread {
+        val finishCallback = mock<Function1<Animator, Unit>>()
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, MINIMIZE_CHANGE))
+
+        val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback)
+
+        animators.forEach { animator ->
+            animator.start()
+            animator.end()
+            verify(finishCallback).invoke(animator)
+        }
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX)
-    fun trampolineTransition_flagEnabled_returnsLaunchAndCloseAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val closeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_CLOSE
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
-        transitionInfo.addChange(closeChange)
+    fun trampolineTransition_flagEnabled_returnsLaunchAndCloseAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -155,21 +159,24 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX)
+    fun trampolineTransition_flagEnabled_callsAnimationEndListener() = runOnUiThread {
+        val finishCallback = mock<Function1<Animator, Unit>>()
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE))
+
+        val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback)
+
+        animators.forEach { animator ->
+            animator.start()
+            animator.end()
+            verify(finishCallback).invoke(animator)
+        }
+    }
+
+    @Test
     @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX)
-    fun trampolineTransition_flagDisabled_returnsLaunchAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val closeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_CLOSE
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
-        transitionInfo.addChange(closeChange)
+    fun trampolineTransition_flagDisabled_returnsLaunchAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -179,26 +186,9 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX)
-    fun trampolineTransition_flagEnabled_hitDesktopWindowLimit_returnsLaunchMinimizeCloseAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val minimizeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_TO_BACK
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val closeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_CLOSE
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
-        transitionInfo.addChange(minimizeChange)
-        transitionInfo.addChange(closeChange)
+    fun trampolineTransition_flagEnabled_hitDesktopWindowLimit_returnsLaunchMinimizeCloseAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(
+            listOf(OPEN_CHANGE, MINIMIZE_CHANGE, CLOSE_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -210,26 +200,9 @@
 
     @Test
     @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX)
-    fun trampolineTransition_flagDisabled_hitDesktopWindowLimit_returnsLaunchMinimizeAnimator() {
-        val openChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_OPEN
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val minimizeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_TO_BACK
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val closeChange =
-            TransitionInfo.Change(mock(), mock()).apply {
-                mode = WindowManager.TRANSIT_CLOSE
-                taskInfo = TASK_INFO_FREEFORM
-            }
-        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
-        transitionInfo.addChange(openChange)
-        transitionInfo.addChange(minimizeChange)
-        transitionInfo.addChange(closeChange)
+    fun trampolineTransition_flagDisabled_hitDesktopWindowLimit_returnsLaunchMinimizeAnimator() = runOnUiThread {
+        val transitionInfo = createTransitionInfo(
+            listOf(OPEN_CHANGE, MINIMIZE_CHANGE, CLOSE_CHANGE))
 
         val actual = helper.createAnimators(transitionInfo, finishCallback = {})
 
@@ -280,6 +253,12 @@
         assertThat(animator.duration).isEqualTo(100)
     }
 
+    private fun createTransitionInfo(changes: List<Change>): TransitionInfo {
+        val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0)
+        changes.forEach { transitionInfo.addChange(it) }
+        return transitionInfo
+    }
+
     private companion object {
         val TASK_INFO_FREEFORM =
             ActivityManager.RunningTaskInfo().apply {
@@ -290,5 +269,23 @@
                 configuration.windowConfiguration.windowingMode =
                     WindowConfiguration.WINDOWING_MODE_FREEFORM
             }
+
+        val OPEN_CHANGE =
+            TransitionInfo.Change(mock(), mock()).apply {
+                mode = WindowManager.TRANSIT_OPEN
+                taskInfo = TASK_INFO_FREEFORM
+            }
+
+        val CLOSE_CHANGE =
+            TransitionInfo.Change(mock(), mock()).apply {
+                mode = WindowManager.TRANSIT_CLOSE
+                taskInfo = TASK_INFO_FREEFORM
+            }
+
+        val MINIMIZE_CHANGE =
+            TransitionInfo.Change(mock(), mock()).apply {
+                mode = WindowManager.TRANSIT_TO_BACK
+                taskInfo = TASK_INFO_FREEFORM
+            }
     }
 }
diff --git a/quickstep/res/drawable/ic_chevron_end.xml b/res/drawable/ic_chevron_end.xml
similarity index 100%
rename from quickstep/res/drawable/ic_chevron_end.xml
rename to res/drawable/ic_chevron_end.xml
diff --git a/quickstep/res/drawable/ic_chevron_start.xml b/res/drawable/ic_chevron_start.xml
similarity index 100%
rename from quickstep/res/drawable/ic_chevron_start.xml
rename to res/drawable/ic_chevron_start.xml
diff --git a/res/layout/work_mode_utility_view.xml b/res/layout/work_mode_utility_view.xml
index b68ff3e..568c2c3 100644
--- a/res/layout/work_mode_utility_view.xml
+++ b/res/layout/work_mode_utility_view.xml
@@ -26,6 +26,7 @@
         android:layout_height="@dimen/work_scheduler_size"
         android:layout_marginBottom="@dimen/work_scheduler_bottom_margin"
         android:contentDescription="@string/work_scheduler_button_content_description"
+        android:elevation="@dimen/work_fab_elevation"
         android:src="@drawable/ic_schedule"
         android:layout_gravity="end"
         android:background="@drawable/work_scheduler_background" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index a2a1cf2..c8ab8ff 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Bladsy %1$d van %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tuisskerm %1$d van %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nuwe tuisskermbladsy"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktief"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Geminimeer"</string>
     <string name="folder_opened" msgid="94695026776264709">"Vouer oopgemaak, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Tik om die vouer toe te maak"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tik om nuwe naam te stoor"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index ac462ac..56e4d56 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"ገፅ %1$d ከ%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"መነሻ ማያ ገፅ %1$d ከ%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"አዲስ የመነሻ ማያ ገፅ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"ገቢር"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"አንሷል"</string>
     <string name="folder_opened" msgid="94695026776264709">"አቃፊ ተከፍቷል፣ <xliff:g id="WIDTH">%1$d</xliff:g> በ<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"አቃፊን ለመዝጋት መታ ያድርጉ"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"ዳግም የተሰጠውን ስም ለማስቀመጥ መታ ያድርጉ"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 6db0ffb..1e4861c 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$dৰ %1$d পৃষ্ঠা"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"গৃহ স্ক্ৰীন %2$dৰ %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"গৃহ স্ক্ৰীনৰ নতুন পৃষ্ঠা"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"সক্ৰিয়"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"মিনিমাইজ কৰা হৈছে"</string>
     <string name="folder_opened" msgid="94695026776264709">"ফ’ল্ডাৰ খোলা হ’ল, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ফ\'ল্ডাৰ বন্ধ কৰিবলৈ টিপক"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"সলনি কৰা নাম ছেভ কৰিবলৈ টিপক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 28035df..916b738 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Səhifə %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Əsas Səhifə ekranı %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni əsas ekran səhifəsi"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Kiçildildi"</string>
     <string name="folder_opened" msgid="94695026776264709">"Qovluq açıldı, <xliff:g id="HEIGHT">%2$d</xliff:g> hündürlük ilə <xliff:g id="WIDTH">%1$d</xliff:g> enində"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Qovluq bağlamaq üçün toxunun"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ad dəyişikliyini yadda saxlamaq üçün toxunun"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index ffb3d91..671cb6d 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Старонка %1$d з %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Галоўны экран %1$d з %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Новая старонка галоўнага экрана"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Актыўна"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Згорнута"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папка адкрыта, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Краніце, каб закрыць папку"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Краніце, каб захаваць новую назву"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 6bc2483..296f088 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dটির %1$d নম্বর হোম স্ক্রিন"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"নতুন হোম স্ক্রীনের পৃষ্ঠা"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"অ্যাক্টিভ"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ছোট করা হয়েছে"</string>
     <string name="folder_opened" msgid="94695026776264709">"ফোল্ডার খোলা হয়েছে, <xliff:g id="WIDTH">%1$d</xliff:g> বাই <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ফোল্ডার বন্ধ করতে আলতো চাপ দিন"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"পুনঃনামকরণ সংরক্ষণ করতে আলতো চাপ দিন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 394e30f..9ab5c4c 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni ekran %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktivno"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizirano"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder je otvoren, (š) <xliff:g id="WIDTH">%1$d</xliff:g> (v) <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da zatvorite folder"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da sačuvate promjenu naziva"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 82bbd12..693c6e5 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktivní"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimalizováno"</string>
     <string name="folder_opened" msgid="94695026776264709">"Složka otevřena, rozměry <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Klepnutím složku zavřete"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Klepnutím změnu názvu uložíte"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 1485f75..bd2bf5a 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d ud af %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskærm %1$d ud af %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny startskærm"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimeret"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen er åben, <xliff:g id="WIDTH">%1$d</xliff:g> gange <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Tryk for at lukke mappen"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tryk for at gemme omdøbningen"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4a7fb7f..ecdc73a 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Seite %1$d von %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startbildschirm %1$d von %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Neue Startbildschirmseite"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimiert"</string>
     <string name="folder_opened" msgid="94695026776264709">"Ordner geöffnet, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Ordner zum Schließen antippen"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Neuen Namen zum Speichern antippen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index de2bdc7..330c23e 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Σελίδα %1$d από %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Αρχική οθόνη %1$d από %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Νέα σελίδα αρχικής οθόνης"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Ενεργό"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Ελαχιστοποιήθηκε"</string>
     <string name="folder_opened" msgid="94695026776264709">"Άνοιγμα φακέλου, <xliff:g id="WIDTH">%1$d</xliff:g> επί <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Πατήστε για να κλείσετε το φάκελο"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Πατήστε για να αποθηκεύσετε τη νέα ονομασία"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 7ce9c0c..6825d80 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -135,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 71fd15a..f383e3f 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -188,10 +188,8 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Close"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Personal apps tab"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Work apps tab"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Work apps are badged and visible to your IT admin"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"Got it"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 7ce9c0c..6825d80 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -135,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 7ce9c0c..6825d80 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -135,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index ef5d483..a287135 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -188,10 +188,8 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Pestaña de apps personales"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Pestaña de apps de trabajo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"Entendido"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index a1ed2ed..e3ab38d 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nueva página de pantalla de inicio"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Activa"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizada"</string>
     <string name="folder_opened" msgid="94695026776264709">"Carpeta abierta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Toca para cerrar la carpeta"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toca para guardar el nuevo nombre"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 5300ec8..3df323d 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Leht %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Avakuva %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uus avakuva leht"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Ühendatud"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimeeritud"</string>
     <string name="folder_opened" msgid="94695026776264709">"Kaust on avatud, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Puudutage kausta sulgemiseks"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Puudutage ümbernimetamise salvestamiseks"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 013c88e..0b30b38 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d orri nagusi"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Orri nagusiaren orri berria"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktibo"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizatuta"</string>
     <string name="folder_opened" msgid="94695026776264709">"Karpeta ireki da: <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Karpeta ixteko, sakatu hau"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Izen berria gordetzeko, sakatu hau"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 578d35d..671c7f2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"‏صفحه %1$d از %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏صفحه اصلی %1$d از %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"صفحه اصلی جدید"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"فعال"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"کوچک‌شده"</string>
     <string name="folder_opened" msgid="94695026776264709">"پوشه باز شده، <xliff:g id="WIDTH">%1$d</xliff:g> در <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"برای بستن پوشه، تک‌ضرب بزنید"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"برای ذخیره تغییر نام، تک‌ضرب بزنید"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 29d04b2..49b2b57 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Sivu %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Aloitusruutu %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uusi aloitusnäytön sivu"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiivinen"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Pienennetty"</string>
     <string name="folder_opened" msgid="94695026776264709">"Kansio avattu, koko <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Sulje kansio koskettamalla."</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tallenna uusi nimi koskettamalla."</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index eb9360f..6c39282 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Actif"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Réduit"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Touchez pour fermer le dossier"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Touchez pour enregistrer le nouveau nom"</string>
@@ -137,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Autoriser la rotation de l\'écran d\'accueil"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"Mode paysage"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"Configurer le téléphone en mode paysage"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"Configurez le téléphone en mode paysage"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Pastilles de notification"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activé"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Désactivé"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index fea7ff1..73902b4 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Actif"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimisé"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Appuyez pour fermer le dossier."</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Appuyez pour enregistrer le nouveau nom du dossier."</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 513083a..1619b14 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova páxina da pantalla de inicio"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Activa"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizada"</string>
     <string name="folder_opened" msgid="94695026776264709">"Abriuse o cartafol, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Toca fóra para pechar o cartafol"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toca fóra para cambiar o nome do cartafol"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index d31f291..bd40d19 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d માંથી %1$d પૃષ્ઠ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d માંથી %1$d હોમ સ્ક્રીન"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"નવું હોમ સ્ક્રીન પૃષ્ઠ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"સક્રિય"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ન્યૂનતમ"</string>
     <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> બાય <xliff:g id="HEIGHT">%2$d</xliff:g> નું ફોલ્ડર ખોલ્યું"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ફોલ્ડર બંધ કરવા માટે ટૅપ કરો"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"નામ બદલવાનું સાચવવા માટે ટૅપ કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 360ef33..15485a2 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"पेज %2$d में से %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"होम स्क्रीन %2$d में से %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नया होम स्‍क्रीन पेज"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"चालू है"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"छोटा किया गया"</string>
     <string name="folder_opened" msgid="94695026776264709">"फ़ोल्डर खोला गया, <xliff:g id="WIDTH">%1$d</xliff:g> गुणा <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"फ़ोल्डर बंद करने के लिए टैप करें"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"नाम बदलना सहेजने के लिए टैप करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index db82c46..48069a2 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Stranica %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni zaslon %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog zaslona"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktivno"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizirano"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mapa je otvorena, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da biste zatvorili mapu"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da biste spremili promijenjeni naziv"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 04e43a7..a298738 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d/%1$d. oldal"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d/%1$d. kezdőképernyő"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Új kezdőképernyő oldal"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktív"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Kis méret"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappa megnyitva – szélesség: <xliff:g id="WIDTH">%1$d</xliff:g>; magasság: <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Érintse meg a mappa bezárásához"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Koppintson ide az átnevezés mentéséhez"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 28a01ac..047c074 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Halaman layar utama baru"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktif"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Diperkecil"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Ketuk untuk menutup folder"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketuk untuk menyimpan ganti nama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index a87df93..19b967f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -188,10 +188,8 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Loka"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persónulegt"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Flipi forrita til einkanota"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Flipi vinnuforrita"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Vinnuforrit eru merkt og kerfisstjórinn getur séð þau"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"Ég skil"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index ffe7436..fd747d1 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -188,10 +188,8 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Esci"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personali"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Scheda App personali"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Scheda App di lavoro"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Le app di lavoro sono contrassegnate con un badge e visibili all\'amministratore IT"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index dd496c8..e829738 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"‏דף %1$d מתוך %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏מסך הבית %1$d מתוך %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"מסך הבית חדש"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"פעיל"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ממוזער"</string>
     <string name="folder_opened" msgid="94695026776264709">"תיקייה פתוחה, <xliff:g id="WIDTH">%1$d</xliff:g> על <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"יש ללחוץ כדי לסגור את התיקייה"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"יש ללחוץ כדי לשמור שינוי שם"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9000081..1e530cd 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -135,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"ホーム画面の回転を許可"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"スマートフォンの向きに合わせます"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"横表示"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"スマートフォンを横表示にしてください"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"スマートフォンを横表示にします"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"通知ドット"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"ON"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"OFF"</string>
@@ -188,10 +188,8 @@
     <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>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"個人用アプリのタブ"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"仕事用アプリのタブ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"仕事用アプリはバッジ付きで表示され、IT 管理者に公開されます"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 2fd6b77..4cd473b 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -188,10 +188,8 @@
     <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>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"პირადი აპების ჩანართი"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"სამსახურის აპების ჩანართი"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"სამსახურის აპები ბეჯით არის მონიშნული და ხილულია თქვენი IT ადმინისტრატორისთვის"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"გასაგებია"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index fee3a9a..c60376b 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d бет, барлығы %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d негізгі экран, барлығы %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Жаңа негізгі экран беті"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Белсенді"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Кішірейтілген"</string>
     <string name="folder_opened" msgid="94695026776264709">"Қалта ашылды, <xliff:g id="WIDTH">%1$d</xliff:g> және <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Қалтаны жабу үшін түртіңіз"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Қайта атауды сақтау үшін түртіңіз"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index cc8539e..5dbae5f 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"ទំព័រ %1$d នៃ %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"អេក្រង់​ដើម %1$d នៃ %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ទំព័រអេក្រង់ដើមថ្មី"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"សកម្ម"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"បានបង្រួម"</string>
     <string name="folder_opened" msgid="94695026776264709">"បាន​បើក​ថត <xliff:g id="WIDTH">%1$d</xliff:g> ដោយ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ប៉ះ ដើម្បីបិទថត"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"ប៉ះដើម្បីរក្សាទុកឈ្មោះដែលបានប្តូរ"</string>
@@ -190,10 +188,8 @@
     <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>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"ផ្ទាំងកម្មវិធី​ផ្ទាល់ខ្លួន"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"ផ្ទាំងកម្មវិធី​ការងារ"</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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e588634..24053c8 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"페이지 %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"홈 화면 %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"새로운 홈 화면 페이지"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"활성"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"최소화"</string>
     <string name="folder_opened" msgid="94695026776264709">"폴더 열림(<xliff:g id="WIDTH">%1$d</xliff:g>X<xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"탭하여 폴더 닫기"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"탭하여 변경된 이름 저장"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index fb1675e..2ad0668 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ичинен %1$d барак"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Үй экраны %2$d ичинен %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Жаңы башкы экран барагы"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Жигердүү"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Кичирейтилди"</string>
     <string name="folder_opened" msgid="94695026776264709">"Фолдер ачылды, туурасы <xliff:g id="WIDTH">%1$d</xliff:g>, бийиктиги <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Куржунду жабуу үчүн таптаңыз"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Өзгөртүлгөн аталышын сактоо үчүн таптаңыз"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 0ba127d..e1b9b34 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. lapa no %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Sākuma ekrāns: %1$d no %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Jauna sākuma ekrāna lapa"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktīva"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizēta"</string>
     <string name="folder_opened" msgid="94695026776264709">"Atvērta mape: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Pieskarieties, lai aizvērtu mapi."</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Pieskarieties, lai saglabātu jauno nosaukumu."</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index ba119f7..8ab50b8 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d од %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Екран на почетна страница %1$d од %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова страница на почетен екран"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Активно"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Минимизирано"</string>
     <string name="folder_opened" msgid="94695026776264709">"Отворена е папка, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Допрете за да ја затворите папката"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Допрете за да го зачувате преименувањето"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 2a2e050..d6df3ac 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"പേജ് %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ഹോം സ്‌ക്രീൻ %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"പുതിയ ഹോം സ്ക്രീൻ പേജ്"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"സജീവം"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ചെറുതാക്കി"</string>
     <string name="folder_opened" msgid="94695026776264709">"ഫോൾഡർ തുറന്നു, <xliff:g id="WIDTH">%1$d</xliff:g> / <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ഫോൾഡർ അടയ്ക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"പേരുമാറ്റം സംരക്ഷിക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index ffe1b2c..7803296 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d-н %1$d хуудас"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d-н Нүүр дэлгэц %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Шинэ үндсэн нүүр хуудас"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Идэвхтэй"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Жижгэрүүлсэн"</string>
     <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> <xliff:g id="HEIGHT">%2$d</xliff:g> фолдер нээгдэв"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Фолдерийг хаахын тулд дарна уу"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Шинэ нэрийг хадгалахын тулд дарна уу."</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index b249150..b0cda77 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पेज"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नवीन होम स्क्रीन पेज"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"अ‍ॅक्टिव्ह"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"लहान केलेले"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डर बंद करण्यासाठी टॅप करा"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे सेव्ह करण्यासाठी टॅप करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 3585ec7..c4d97d5 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -188,10 +188,8 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Tutup"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Peribadi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Tab apl peribadi"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Tab apl kerja"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Apl kerja mempunyai lencana dan kelihatan kepada pentadbir IT anda"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 0116834..75e87f4 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"စာမျက်နှာ %1$d မှ %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ပင်မစာမျက်နှာ %1$d မှ %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"သုံးနေသည်"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ချုံ့ထားသည်"</string>
     <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ဖိုင်တွဲကို ပိတ်ရန် တို့ပါ"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းရန် တို့ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 47c6abb..d7497cd 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startside %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny side på startskjermen"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimert"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen er åpnet – <xliff:g id="WIDTH">%1$d</xliff:g> ganger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Trykk for å lukke mappen"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Trykk for å lagre det nye navnet"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e451926..bbe8233 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d को %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"होम स्क्रिन %1$d को %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नयाँ होम स्क्रिन पृष्ठ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"सक्रिय"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"सानो पारिएको"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डरलाई बन्द गर्न ट्याप गर्नुहोस्"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनःनामाकरणलाई सुरक्षित गर्न ट्याप गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 75793b0..971eee9 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -135,7 +135,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Draaien van startscherm toestaan"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Als de telefoon gedraaid is"</string>
     <string name="landscape_mode_title" msgid="5138814555934843926">"Liggende modus"</string>
-    <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefoon instellen op liggende modus"</string>
+    <string name="landscape_mode_desc" msgid="7372569859592816793">"Stel telefoon in op liggende modus"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Meldingsstipjes"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"Aan"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Uit"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 98ccaf1..d5b87dc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"ମୋଟ %2$dରୁ %1$d ନମ୍ବର ପୃଷ୍ଠା"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dରୁ %1$d ହୋମ ସ୍କ୍ରିନ"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ନୂଆ ହୋମ ସ୍କ୍ରିନ ପେଜ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"ସକ୍ରିୟ"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ଛୋଟ କରାଯାଇଛି"</string>
     <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="HEIGHT">%2$d</xliff:g> / <xliff:g id="WIDTH">%1$d</xliff:g>ର ଫୋଲ୍ଡର ଖୋଲାଗଲା"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ଫୋଲ୍ଡର୍‌ ବନ୍ଦ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"ନାମ ବଦଳାଇବା ସେଭ୍ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 3904473..a9b089b 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"ਸਫ਼ਾ %2$d ਦਾ %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ਹੋਮ ਸਕ੍ਰੀਨ %2$d ਦੀ %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ਨਵਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਸਫ਼ਾ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"ਕਿਰਿਆਸ਼ੀਲ"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"ਛੋਟਾ ਕੀਤਾ ਗਿਆ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ਫੋਲਡਰ ਖੋਲ੍ਹਿਆ, <xliff:g id="WIDTH">%1$d</xliff:g> ਬਾਇ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ਫੋਲਡਰ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"ਬਦਲੇ ਗਏ ਨਾਮ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f7f71f4..7860464 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Strona %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekran główny %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nowa strona ekranu głównego"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktywna"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Zminimalizowana"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder otwarty, <xliff:g id="WIDTH">%1$d</xliff:g> na <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Kliknij, by zamknąć folder"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Kliknij, by zapisać nową nazwę"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d0e1178..76e6bcf 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tela inicial %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova página na tela inicial"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Ativo"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizado"</string>
     <string name="folder_opened" msgid="94695026776264709">"Pasta aberta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Toque para fechar a pasta"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toque para salvar o novo nome"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 9022d6f..035e8cd 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d din %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecranul de pornire %1$d din %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Pagină nouă pe ecranul de pornire"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Activă"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizată"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dosar deschis, <xliff:g id="WIDTH">%1$d</xliff:g> pe <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Atinge pentru a închide dosarul"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Atinge pentru a salva noul nume"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 7e64c0d..db885f4 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d හි %1$d පිටුව"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"මුල් පිටු තිරය %2$d හි %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"නව මුල් පිටුව"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"සක්‍රිය"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"කුඩා කරන ලදි"</string>
     <string name="folder_opened" msgid="94695026776264709">"ෆෝල්ඩරය විවෘත විය, <xliff:g id="WIDTH">%1$d</xliff:g> හි <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ෆෝල්ඩරය වැසීමට තට්ටු කරන්න"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"යළි නම් කිරීම සුරැකීමට තට්ටු කරන්න"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index ac47b0a..2109538 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Faqja: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekrani bazë: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Faqja e ekranit të ri kryesor"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizuar"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dosja u hap, <xliff:g id="WIDTH">%1$d</xliff:g> me <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Trokit për të mbyllur dosjen"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Trokit për të ruajtur riemërtimin"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 7c676e9..f2d0ed9 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Sidan %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskärmen %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny sida på startskärmen"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktivt"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Minimerat"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen är öppen, <xliff:g id="WIDTH">%1$d</xliff:g> gånger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Tryck för att stänga mappen"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tryck för att spara namnändringen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 06ba981..6a5aa13 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Ukurasa%1$d wa %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrini ya mwanzo %1$d ya %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ukurasa mpya wa skrini ya kwanza"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Inatumika"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Imepunguzwa"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Gusa ili ufunge folda"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Gusa ili ubadilishe jina"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 4bb86da..890e280 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"பக்கம் %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"புதிய முகப்புத் திரை பக்கம்"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"செயலில் உள்ளது"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"சிறிதாக்கப்பட்டது"</string>
     <string name="folder_opened" msgid="94695026776264709">"திறக்கப்பட்ட ஃபோல்டர், <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ஃபோல்டரை மூட, தட்டவும்"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"மாற்றிய பெயரைச் சேமிக்க, தட்டவும்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index cd4f456..63d25f7 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -188,10 +188,8 @@
     <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>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"వ్యక్తిగత యాప్‌ల ట్యాబ్"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"వర్క్ యాప్‌ల ట్యాబ్"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"వర్క్ యాప్‌లకు బ్యాడ్జ్ ఉంటుంది, అవి మీ IT అడ్మిన్‌కు కనిపిస్తాయి"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"అర్థమైంది"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index b8a0df4..27b171b 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Pahina %1$d ng %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d ng %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Bagong page ng home screen"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Aktibo"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Na-minimize"</string>
     <string name="folder_opened" msgid="94695026776264709">"Binuksan ang folder, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"I-tap upang isara ang folder"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"I-tap upang i-save ang bagong pangalan"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 5bd7c52..a1bc2b7 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Sayfa %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ana ekran %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni ana ekran sayfası"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Etkin"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Simge durumuna küçültülmüş"</string>
     <string name="folder_opened" msgid="94695026776264709">"Klasör açıldı, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Klasörü kapatmak için dokunun"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Yeni adın kaydedilmesi için dokunun"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 798c567..389dd75 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Сторінка %1$d з %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Головний екран %1$d з %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова сторінка головного екрана"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Додаток активний"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Додаток згорнуто"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папку відкрито (<xliff:g id="WIDTH">%1$d</xliff:g> х <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Торкніться, щоб закрити папку"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Торкніться, щоб зберегти зміни"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index ec5129d..724cbcd 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"‏صفحہ ‎%1$d از ‎%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏ہوم اسکرین ‎%1$d از ‎%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"نیا ہوم اسکرین صفحہ"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"فعال"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"کم کر دیا گیا"</string>
     <string name="folder_opened" msgid="94695026776264709">"فولڈر کھولا گیا، <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"فولڈر کو بند کرنے کیلئے تھپتھپائیں"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"نام کی تبدیلی محفوظ کرنے کیلئے تھپتھپائیں"</string>
@@ -190,10 +188,8 @@
     <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>
-    <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) -->
-    <skip />
-    <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) -->
-    <skip />
+    <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"ذاتی ایپس کا ٹیب"</string>
+    <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"ورک ایپس کا ٹیب"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"‏ورک ایپس پر بَیج لگا ہوتا ہے اور آپ کا IT منتظم انہیں دیکھ سکتا ہے"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"سمجھ آ گئی"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 48068d6..67c96ef 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yangi bosh ekran sahifasi"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Faol"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Yigʻilgan"</string>
     <string name="folder_opened" msgid="94695026776264709">"Jild ochildi, <xliff:g id="WIDTH">%1$d</xliff:g> ga <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Jildni yopish uchun ustiga bosing"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"O‘zgarishni saqlash uchun ustiga bosing"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5b88099..3074222 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Trang %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Màn hình chính %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Trang màn hình chính mới"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Đang hoạt động"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Đã thu nhỏ"</string>
     <string name="folder_opened" msgid="94695026776264709">"Đã mở thư mục, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Nhấn để đóng thư mục"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Nhấn để lưu đổi tên"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 7b51d1d..bed166c 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"第%1$d页,共%2$d页"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主屏幕:第%1$d屏,共%2$d屏"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"主屏幕新页面"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"活跃"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"已最小化"</string>
     <string name="folder_opened" msgid="94695026776264709">"文件夹已打开,大小为<xliff:g id="WIDTH">%1$d</xliff:g>×<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"点按可关闭文件夹"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"点按可保存新名称"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 0dd1801..07c6386 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主畫面 %1$d,共 %2$d 個"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"新主畫面頁面"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"運作中"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"已縮到最小"</string>
     <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"輕按即可關閉資料夾"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"輕按即可儲存新名稱"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 424939b..c3ffbc1 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主畫面:第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"新的主畫面頁面"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"運作中"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"最小化"</string>
     <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"輕觸即可關閉資料夾"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"輕觸即可儲存新名稱"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 918b7ca..d08a21e 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -117,10 +117,8 @@
     <string name="default_scroll_format" msgid="7475544710230993317">"Ikhasi elingu-%1$d kwangu-%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Isikrini sasekhaya esingu-%1$d se-%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ikhasi elisha lesikrini sasekhaya"</string>
-    <!-- no translation found for app_running_state_description (5645053189564740904) -->
-    <skip />
-    <!-- no translation found for app_minimized_state_description (710740620044902509) -->
-    <skip />
+    <string name="app_running_state_description" msgid="5645053189564740904">"Kuyasebenza"</string>
+    <string name="app_minimized_state_description" msgid="710740620044902509">"Kuncishisiwe"</string>
     <string name="folder_opened" msgid="94695026776264709">"Ifolda ivuliwe, <xliff:g id="WIDTH">%1$d</xliff:g> nge-<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Thepa ukuze uvale ifolda"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"Thepha ukuze ulondoloze ukuqamba kabusha"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index a22f943..1ecac33 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -19,6 +19,7 @@
 
     <!-- Attributes used for launcher theme -->
     <attr name="allAppsScrimColor" format="color" />
+    <attr name="allAppsScrimColorOverBlur" format="color" />
     <attr name="allappsHeaderProtectionColor" format="color" />
     <attr name="allAppsNavBarScrimColor" format="color" />
     <attr name="allAppsTheme" format="reference" />
diff --git a/res/values/config.xml b/res/values/config.xml
index d65580c..3b48c9e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -224,4 +224,7 @@
          of the same name in SystemUI. -->
     <string-array name="config_appsSupportMultiInstancesSplit">
     </string-array>
+
+    <!-- Used to differentiate between desktop and non-desktop devices. -->
+    <bool name="desktop_form_factor">false</bool>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cc740a5..a626097 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -323,6 +323,8 @@
     <string name="edit_home_screen">Edit Home Screen</string>
     <!-- Text for settings button [CHAR LIMIT=20]-->
     <string name="settings_button_text">Home settings</string>
+    <!-- Text for app menu button [CHAR LIMIT=30]-->
+    <string name="all_apps_home_screen">Apps</string>
     <!-- Message shown when a feature is disabled by the administrator -->
     <string name="msg_disabled_by_admin">Disabled by your admin</string>
 
@@ -469,6 +471,12 @@
     <!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_deep_shortcut">Shortcut Menu</string>
 
+    <!-- Accessibility name for the app widget resize frame. -->
+    <string name="widget_frame_name">Widget Resize Frame for <xliff:g id="string" example="Clock">%1$s</xliff:g></string>
+
+    <!-- Accessibility action to close the widget resize frame. [CHAR_LIMIT=30] -->
+    <string name="action_close">Close</string>
+
     <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_dismiss_notification">Dismiss</string>
 
@@ -541,4 +549,5 @@
     <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>
+    <string name="ps_app_content_description">Add files and more to Private Space</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 04421c0..39206d3 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -40,6 +40,7 @@
     <style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
         <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item>
+        <item name="allAppsScrimColorOverBlur">#33000000</item>
         <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerHighest</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
@@ -114,6 +115,7 @@
         <item name="android:colorControlHighlight">#19FFFFFF</item>
         <item name="android:colorPrimary">#FF212121</item>
         <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item>
+        <item name="allAppsScrimColorOverBlur">#52000000</item>
         <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerLow</item>
         <item name="allAppsNavBarScrimColor">#80000000</item>
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index b51e850..213d88f 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -216,6 +216,13 @@
         AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
                 .inflate(R.layout.app_widget_resize_frame, dl, false);
         frame.setupForWidget(widget, cellLayout, dl);
+        // Save widget item info as tag on resize frame; so that, the accessibility delegate can
+        // attach actions that typically happen on widget (e.g. resize, move) also on the resize
+        // frame.
+        frame.setTag(widget.getTag());
+        frame.setAccessibilityDelegate(launcher.getAccessibilityDelegate());
+        frame.setContentDescription(launcher.asContext().getString(R.string.widget_frame_name,
+                widget.getContentDescription()));
         ((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
 
         dl.addView(frame);
@@ -235,6 +242,13 @@
         }
     }
 
+    /**
+     *  Retrieves the view where accessibility actions happen.
+     */
+    public View getViewForAccessibility() {
+        return mWidgetView;
+    }
+
     private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
             DragLayer dragLayer) {
         mCellLayout = cellLayout;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 783e82c..30e3a2b 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.BubbleTextView.RunningAppState.MINIMIZED;
 import static com.android.launcher3.Flags.enableContrastTiles;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.allapps.AlphabeticalAppsList.PRIVATE_SPACE_PACKAGE;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_SKIP_USER_BADGE;
@@ -104,6 +105,7 @@
 import java.text.NumberFormat;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
@@ -589,7 +591,9 @@
     }
 
     private void setNonPendingIcon(ItemInfoWithIcon info) {
-        int flags = shouldUseTheme() ? FLAG_THEMED : info.bitmap.creationFlags;
+        // Set nonPendingIcon acts as a restart which should refresh the flag state when applicable.
+        int flags = Objects.equals(info.getTargetPackage(), PRIVATE_SPACE_PACKAGE)
+                ? info.bitmap.creationFlags : shouldUseTheme() ? FLAG_THEMED : 0;
         // Remove badge on icons smaller than 48dp.
         if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) {
             flags |= FLAG_NO_BADGE;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c85ca49..090208a 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -30,8 +30,8 @@
 import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp;
 import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat;
 import static com.android.wm.shell.Flags.enableBubbleBar;
-import static com.android.wm.shell.Flags.enableTinyTaskbar;
 import static com.android.wm.shell.Flags.enableBubbleBarOnPhones;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -508,9 +508,11 @@
 
         bottomSheetOpenDuration = res.getInteger(R.integer.config_bottomSheetOpenDuration);
         bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration);
-        if (isTablet) {
+        if (shouldShowAllAppsOnSheet()) {
             bottomSheetWorkspaceScale = workspaceContentScale;
-            if (isMultiDisplay) {
+            if (Flags.allAppsBlur()) {
+                bottomSheetDepth = 2f;
+            } else if (isMultiDisplay) {
                 // TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth
                 // when screen recorder bug is fixed.
                 if (enableScalingRevealHomeAnimation()) {
@@ -1830,10 +1832,17 @@
                         workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace;
             }
             int paddingTop = workspaceTopPadding + (mIsScalableGrid ? 0 : edgeMarginPx);
-            // On isFixedLandscapeMode on phones we already have padding because of the camera hole
-            int paddingSide = inv.isFixedLandscape ? 0 : desiredWorkspaceHorizontalMarginPx;
+            int paddingLeft = desiredWorkspaceHorizontalMarginPx;
+            int paddingRight = desiredWorkspaceHorizontalMarginPx;
 
-            padding.set(paddingSide, paddingTop, paddingSide, paddingBottom);
+            // In fixed Landscape we don't need padding on the side next to the cutout because
+            // the cutout is already adding padding to all of Launcher, we only need on the other
+            // side
+            if (inv.isFixedLandscape) {
+                paddingLeft = isSeascape() ? desiredWorkspaceHorizontalMarginPx : 0;
+                paddingRight = isSeascape() ? 0 : desiredWorkspaceHorizontalMarginPx;
+            }
+            padding.set(paddingLeft, paddingTop, paddingRight, paddingBottom);
         }
         insetPadding(workspacePadding, cellLayoutPaddingPx);
     }
@@ -1931,7 +1940,24 @@
                 hotseatBarPadding.set(mHotseatBarWorkspaceSpacePx, paddingTop,
                         mInsets.right + mHotseatBarEdgePaddingPx, paddingBottom);
             }
-        } else if (isTaskbarPresent || inv.isFixedLandscape) {
+        } else if (inv.isFixedLandscape) {
+            // Center the QSB vertically with hotseat
+            int hotseatBarBottomPadding = getHotseatBarBottomPadding();
+            int hotseatPlusQSBWidth = getHotseatRequiredWidth();
+            int qsbWidth = getAdditionalQsbSpace();
+            int availableWidthPxForHotseat = availableWidthPx - Math.abs(workspacePadding.width())
+                    - Math.abs(cellLayoutPaddingPx.width());
+            int remainingSpaceOnSide = (availableWidthPxForHotseat - hotseatPlusQSBWidth) / 2;
+
+            hotseatBarPadding.set(
+                    (remainingSpaceOnSide + qsbWidth) + mInsets.left + workspacePadding.left
+                            + cellLayoutPaddingPx.left,
+                    hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx,
+                    remainingSpaceOnSide + mInsets.right + workspacePadding.right
+                            + cellLayoutPaddingPx.right,
+                    hotseatBarBottomPadding
+            );
+        } else if (isTaskbarPresent) {
             // Center the QSB vertically with hotseat
             int hotseatBarBottomPadding = getHotseatBarBottomPadding();
             int hotseatBarTopPadding =
@@ -1950,11 +1976,6 @@
             }
             startSpacing += getAdditionalQsbSpace();
 
-            if (inv.isFixedLandscape) {
-                endSpacing += mInsets.right;
-                startSpacing +=  mInsets.left;
-            }
-
             hotseatBarPadding.top = hotseatBarTopPadding;
             hotseatBarPadding.bottom = hotseatBarBottomPadding;
             boolean isRtl = Utilities.isRtl(context.getResources());
@@ -2164,7 +2185,8 @@
     }
 
     public boolean isSeascape() {
-        return rotationHint == Surface.ROTATION_270 && isVerticalBarLayout();
+        return rotationHint == Surface.ROTATION_270
+                && (isVerticalBarLayout() || inv.isFixedLandscape);
     }
 
     public boolean shouldFadeAdjacentWorkspaceScreens() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 289f175..5c9392d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1472,8 +1472,7 @@
             // Adding a shortcut to a Folder.
             FolderIcon folderIcon = findFolderIcon(container);
             if (folderIcon != null) {
-                FolderInfo folderInfo = (FolderInfo) folderIcon.getTag();
-                folderInfo.add(info, args.rank, false);
+                folderIcon.getFolder().addFolderContent(info, args.rank, false);
             } else {
                 Log.e(TAG, "Could not find folder with id " + container + " to add shortcut.");
             }
@@ -1792,7 +1791,6 @@
         SettingsCache.INSTANCE.get(this).unregister(TOUCHPAD_NATURAL_SCROLLING,
                 mNaturalScrollingChangedListener);
         ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
-        mWorkspace.removeFolderListeners();
         PluginManagerWrapper.INSTANCE.get(this).removePluginListener(this);
 
         mModel.removeCallbacks(this);
@@ -2053,9 +2051,10 @@
             @Nullable final String reason) {
         if (itemInfo instanceof WorkspaceItemInfo) {
             View collectionIcon = mWorkspace.getViewByItemId(itemInfo.container);
-            if (collectionIcon instanceof FolderIcon) {
+            if (collectionIcon instanceof FolderIcon folderIcon) {
                 // Remove the shortcut from the folder before removing it from launcher
-                ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+                Folder folder = folderIcon.getFolder();
+                folder.removeFolderContent(true, itemInfo);
             } else if (collectionIcon instanceof AppPairIcon appPairIcon) {
                 removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb,
                         "removing app pair because one of its member apps was removed");
@@ -2066,9 +2065,6 @@
                 getModelWriter().deleteItemFromDatabase(itemInfo, reason);
             }
         } else if (itemInfo instanceof CollectionInfo ci) {
-            if (v instanceof FolderIcon) {
-                ((FolderIcon) v).removeListeners();
-            }
             mWorkspace.removeWorkspaceItem(v);
             if (deleteFromDb) {
                 getModelWriter().deleteCollectionAndContentsFromDatabase(ci);
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index add0ad8..557ad67 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -28,11 +28,12 @@
 import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.AddWorkspaceItemsTask
 import com.android.launcher3.model.AllAppsList
-import com.android.launcher3.model.BaseLauncherBinder
+import com.android.launcher3.model.BaseLauncherBinder.BaseLauncherBinderFactory
 import com.android.launcher3.model.BgDataModel
 import com.android.launcher3.model.CacheDataUpdatedTask
 import com.android.launcher3.model.ItemInstallQueue
 import com.android.launcher3.model.LoaderTask
+import com.android.launcher3.model.LoaderTask.LoaderTaskFactory
 import com.android.launcher3.model.ModelDbController
 import com.android.launcher3.model.ModelDelegate
 import com.android.launcher3.model.ModelInitializer
@@ -43,6 +44,8 @@
 import com.android.launcher3.model.ReloadStringCacheTask
 import com.android.launcher3.model.ShortcutsChangedTask
 import com.android.launcher3.model.UserLockStateChangedTask
+import com.android.launcher3.model.UserManagerState
+import com.android.launcher3.model.WorkspaceItemSpaceFinder
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.pm.UserCache
@@ -70,30 +73,24 @@
 @Inject
 constructor(
     @ApplicationContext private val context: Context,
-    private val appProvider: Provider<LauncherAppState>,
+    private val taskControllerProvider: Provider<ModelTaskController>,
     private val iconCache: IconCache,
     private val prefs: LauncherPrefs,
     private val installQueue: ItemInstallQueue,
-    appFilter: AppFilter,
     @Named("ICONS_DB") dbFileName: String?,
     initializer: ModelInitializer,
     lifecycle: DaggerSingletonTracker,
     val modelDelegate: ModelDelegate,
+    private val mBgAllAppsList: AllAppsList,
+    private val mBgDataModel: BgDataModel,
+    private val loaderFactory: LoaderTaskFactory,
+    private val binderFactory: BaseLauncherBinderFactory,
+    private val spaceFinderFactory: Provider<WorkspaceItemSpaceFinder>,
+    val modelDbController: ModelDbController,
 ) {
 
     private val mCallbacksList = ArrayList<BgDataModel.Callbacks>(1)
 
-    // < only access in worker thread >
-    private val mBgAllAppsList = AllAppsList(iconCache, appFilter)
-
-    /**
-     * All the static data should be accessed on the background thread, A lock should be acquired on
-     * this object when accessing any data from this model.
-     */
-    private val mBgDataModel = BgDataModel()
-
-    val modelDbController = ModelDbController(context)
-
     private val mLock = Any()
 
     private var mLoaderTask: LoaderTask? = null
@@ -139,7 +136,7 @@
     /** Adds the provided items to the workspace. */
     fun addAndBindAddedWorkspaceItems(itemList: List<Pair<ItemInfo?, Any?>?>) {
         callbacks.forEach { it.preAddApps() }
-        enqueueModelUpdateTask(AddWorkspaceItemsTask(itemList))
+        enqueueModelUpdateTask(AddWorkspaceItemsTask(itemList, spaceFinderFactory.get()))
     }
 
     fun getWriter(
@@ -299,13 +296,7 @@
                 // Clear any pending bind-runnables from the synchronized load process.
                 callbacksList.forEach { MAIN_EXECUTOR.execute(it::clearPendingBinds) }
 
-                val launcherBinder =
-                    BaseLauncherBinder(
-                        appProvider.get(),
-                        mBgDataModel,
-                        mBgAllAppsList,
-                        callbacksList,
-                    )
+                val launcherBinder = binderFactory.createBinder(callbacksList)
                 if (bindDirectly) {
                     // Divide the set of loaded items into those that we are binding synchronously,
                     // and everything else that is to be bound normally (asynchronously).
@@ -317,14 +308,7 @@
                     launcherBinder.bindWidgets()
                     return true
                 } else {
-                    val task =
-                        LoaderTask(
-                            appProvider.get(),
-                            mBgAllAppsList,
-                            mBgDataModel,
-                            this.modelDelegate,
-                            launcherBinder,
-                        )
+                    val task = loaderFactory.newLoaderTask(launcherBinder, UserManagerState())
                     mLoaderTask = task
 
                     // Always post the loader task, instead of running directly
@@ -425,7 +409,7 @@
     /** Called when the labels for the widgets has updated in the icon cache. */
     fun onWidgetLabelsUpdated(updatedPackages: HashSet<String?>, user: UserHandle) {
         enqueueModelUpdateTask { taskController, dataModel, _ ->
-            dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, appProvider.get())
+            dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user)
             taskController.bindUpdatedWidgets(dataModel)
         }
     }
@@ -439,17 +423,7 @@
                 // Loader has not yet run.
                 return@execute
             }
-            task.execute(
-                ModelTaskController(
-                    appProvider.get(),
-                    mBgDataModel,
-                    mBgAllAppsList,
-                    this,
-                    MAIN_EXECUTOR,
-                ),
-                mBgDataModel,
-                mBgAllAppsList,
-            )
+            task.execute(taskControllerProvider.get(), mBgDataModel, mBgAllAppsList)
         }
     }
 
@@ -476,7 +450,7 @@
 
     fun refreshAndBindWidgetsAndShortcuts(packageUser: PackageUserKey?) {
         enqueueModelUpdateTask { taskController, dataModel, _ ->
-            dataModel.widgetsModel.update(taskController.app, packageUser)
+            dataModel.widgetsModel.update(packageUser)
             taskController.bindUpdatedWidgets(dataModel)
         }
     }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 03ecf14..acb2b48 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -26,13 +26,13 @@
 import android.content.ContentValues;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.model.ModelDbController;
@@ -74,24 +74,20 @@
 
     @Override
     public String getType(Uri uri) {
-        SqlArguments args = new SqlArguments(uri, null, null);
-        if (TextUtils.isEmpty(args.where)) {
-            return "vnd.android.cursor.dir/" + args.table;
+        if (TextUtils.isEmpty(parseUri(uri, null, null).first)) {
+            return "vnd.android.cursor.dir/" + Favorites.TABLE_NAME;
         } else {
-            return "vnd.android.cursor.item/" + args.table;
+            return "vnd.android.cursor.item/" + Favorites.TABLE_NAME;
         }
     }
 
     @Override
     public Cursor query(Uri uri, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
-        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
-        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-        qb.setTables(args.table);
-
+        Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
         Cursor[] result = new Cursor[1];
         executeControllerTask(controller -> {
-            result[0] = controller.query(args.table, projection, args.where, args.args, sortOrder);
+            result[0] = controller.query(projection, args.first, args.second, sortOrder);
             return 0;
         });
         return result[0];
@@ -108,7 +104,7 @@
             // attempt allocate and bind the widget.
             Integer itemType = values.getAsInteger(Favorites.ITEM_TYPE);
             if (itemType != null
-                    && itemType.intValue() == Favorites.ITEM_TYPE_APPWIDGET
+                    && itemType == Favorites.ITEM_TYPE_APPWIDGET
                     && !values.containsKey(Favorites.APPWIDGET_ID)) {
 
                 ComponentName cn = ComponentName.unflattenFromString(
@@ -135,8 +131,7 @@
                 }
             }
 
-            SqlArguments args = new SqlArguments(uri);
-            return controller.insert(args.table, values);
+            return controller.insert(values);
         });
 
         return rowId < 0 ? null : ContentUris.withAppendedId(uri, rowId);
@@ -144,14 +139,14 @@
 
     @Override
     public int delete(Uri uri, String selection, String[] selectionArgs) {
-        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
-        return executeControllerTask(c -> c.delete(args.table, args.where, args.args));
+        Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
+        return executeControllerTask(c -> c.delete(args.first, args.second));
     }
 
     @Override
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
-        return executeControllerTask(c -> c.update(args.table, values, args.where, args.args));
+        Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
+        return executeControllerTask(c -> c.update(values, args.first, args.second));
     }
 
     @Override
@@ -209,35 +204,24 @@
         }
     }
 
-    static class SqlArguments {
-        public final String table;
-        public final String where;
-        public final String[] args;
-
-        SqlArguments(Uri url, String where, String[] args) {
-            if (url.getPathSegments().size() == 1) {
-                this.table = url.getPathSegments().get(0);
-                this.where = where;
-                this.args = args;
-            } else if (url.getPathSegments().size() != 2) {
-                throw new IllegalArgumentException("Invalid URI: " + url);
-            } else if (!TextUtils.isEmpty(where)) {
-                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
-            } else {
-                this.table = url.getPathSegments().get(0);
-                this.where = "_id=" + ContentUris.parseId(url);
-                this.args = null;
+    /**
+     * Parses the uri and returns the where and arg clause.
+     *
+     * Note: This should be called on the binder thread (before posting on any executor) so that
+     * any parsing error gets propagated to the caller.
+     */
+    private static Pair<String, String[]> parseUri(Uri url, String where, String[] args) {
+        switch (url.getPathSegments().size()) {
+            case 1 -> {
+                return Pair.create(where, args);
             }
-        }
-
-        SqlArguments(Uri url) {
-            if (url.getPathSegments().size() == 1) {
-                table = url.getPathSegments().get(0);
-                where = null;
-                args = null;
-            } else {
-                throw new IllegalArgumentException("Invalid URI: " + url);
+            case 2 -> {
+                if (!TextUtils.isEmpty(where)) {
+                    throw new UnsupportedOperationException("WHERE clause not supported: " + url);
+                }
+                return Pair.create("_id=" + ContentUris.parseId(url), null);
             }
+            default -> throw new IllegalArgumentException("Invalid URI: " + url);
         }
     }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9a9bc1d..d6ae3a6 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -100,6 +100,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.function.Predicate;
 
 /**
@@ -276,8 +277,12 @@
      */
     public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
         sMatrix.reset();
+        //TODO(b/307488755) when implemented this check should be removed
+        if (!Objects.equals(descendant.getWindowId(), root.getWindowId())) {
+            return;
+        }
         View v = descendant;
-        while(v != root) {
+        while (v != root) {
             sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
             sMatrix.postConcat(v.getMatrix());
             sMatrix.postTranslate(v.getLeft(), v.getTop());
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6ed183a..59f84ab 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -137,7 +137,6 @@
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import java.util.stream.Collectors;
 
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -659,7 +658,6 @@
         }
 
         // Remove the pages and clear the screen models
-        removeFolderListeners();
         removeAllViews();
         mScreenOrder.clear();
         mWorkspaceScreens.clear();
@@ -1914,7 +1912,7 @@
 
         boolean aboveShortcut = Folder.willAccept(dropOverView.getTag())
                 && ((ItemInfo) dropOverView.getTag()).container != CONTAINER_HOTSEAT_PREDICTION;
-        boolean willBecomeShortcut = Folder.willAcceptItemType(info.itemType);
+        boolean willBecomeShortcut = FolderInfo.willAcceptItemType(info.itemType);
 
         return (aboveShortcut && willBecomeShortcut);
     }
@@ -1994,8 +1992,8 @@
                 fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale);
             } else {
                 fi.prepareCreateAnimation(v);
-                fi.addItem(destInfo);
-                fi.addItem(sourceInfo);
+                fi.getFolder().addFolderContent(destInfo);
+                fi.getFolder().addFolderContent(sourceInfo);
             }
             return true;
         }
@@ -3209,21 +3207,6 @@
         });
     }
 
-    /**
-     * Removes all folder listeners
-     */
-    public void removeFolderListeners() {
-        mapOverItems(new ItemOperator() {
-            @Override
-            public boolean evaluate(ItemInfo info, View view) {
-                if (view instanceof FolderIcon) {
-                    ((FolderIcon) view).removeListeners();
-                }
-                return false;
-            }
-        });
-    }
-
     public boolean isDropEnabled() {
         return true;
     }
@@ -3349,15 +3332,15 @@
                     if (child instanceof DropTarget) {
                         mDragController.removeDropTarget((DropTarget) child);
                     }
-                } else if (child instanceof FolderIcon) {
+                } else if (child instanceof FolderIcon folderIcon) {
                     FolderInfo folderInfo = (FolderInfo) info;
-                    List<ItemInfo> matches = folderInfo.getContents().stream()
+                    ItemInfo[] matches = folderInfo.getContents().stream()
                             .filter(matcher)
-                            .collect(Collectors.toList());
-                    if (!matches.isEmpty()) {
-                        folderInfo.removeAll(matches, false);
-                        if (((FolderIcon) child).getFolder().isOpen()) {
-                            ((FolderIcon) child).getFolder().close(false /* animate */);
+                            .toArray(ItemInfo[]::new);
+                    if (matches.length > 0) {
+                        folderIcon.getFolder().removeFolderContent(false, matches);
+                        if (folderIcon.getFolder().isOpen()) {
+                            folderIcon.getFolder().close(false /* animate */);
                         }
                     }
                 } else if (info instanceof AppPairInfo api) {
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 78b53a9..df34ccf 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -25,6 +25,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.ButtonDropTarget;
 import com.android.launcher3.CellLayout;
@@ -82,6 +83,7 @@
     protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
     protected static final int RESIZE = R.id.action_resize;
     public static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
+    public static final int CLOSE = R.id.action_close;
 
     public LauncherAccessibilityDelegate(Launcher launcher) {
         super(launcher);
@@ -104,6 +106,8 @@
                 RESIZE, R.string.action_resize, KeyEvent.KEYCODE_R));
         mActions.put(DEEP_SHORTCUTS, new LauncherAction(DEEP_SHORTCUTS,
                 R.string.action_deep_shortcut, KeyEvent.KEYCODE_S));
+        mActions.put(CLOSE, new LauncherAction(CLOSE,
+                R.string.action_close, KeyEvent.KEYCODE_X));
     }
 
     private static boolean isNotInShortcutMenu(@Nullable View view) {
@@ -137,6 +141,10 @@
             }
         }
 
+        if (host instanceof AppWidgetResizeFrame) {
+            out.add(mActions.get(CLOSE));
+        }
+
         if (supportAddToWorkSpace(item)) {
             out.add(mActions.get(ADD_TO_WORKSPACE));
         }
@@ -183,22 +191,28 @@
             }
             return dragCondition != null;
         } else if (action == MOVE) {
-            return beginAccessibleDrag(host, item, fromKeyboard);
+            final View itemView = (host instanceof AppWidgetResizeFrame)
+                    ? ((AppWidgetResizeFrame) host).getViewForAccessibility()
+                    : host;
+            return beginAccessibleDrag(itemView, item, fromKeyboard);
         } else if (action == ADD_TO_WORKSPACE) {
             return addToWorkspace(item, true /*accessibility*/, null /*finishCallback*/);
         } else if (action == MOVE_TO_WORKSPACE) {
             return moveToWorkspace(item);
         } else if (action == RESIZE) {
+            final View itemView = (host instanceof AppWidgetResizeFrame)
+                    ? ((AppWidgetResizeFrame) host).getViewForAccessibility()
+                    : host;
             final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
-            List<OptionItem> actions = getSupportedResizeActions(host, info);
+            List<OptionItem> actions = getSupportedResizeActions(itemView, info);
             Rect pos = new Rect();
-            mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
+            mContext.getDragLayer().getDescendantRectRelativeToSelf(itemView, pos);
             ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false);
             popup.requestFocus();
             popup.addOnCloseCallback(() -> {
-                host.requestFocus();
-                host.sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
-                host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
+                itemView.requestFocus();
+                itemView.sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
+                itemView.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
                 AbstractFloatingView.closeOpenViews(mContext, /* animate= */ false,
                         AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME);
             });
@@ -208,6 +222,11 @@
                     : (host instanceof BubbleTextHolder
                             ? ((BubbleTextHolder) host).getBubbleText() : null);
             return btv != null && PopupContainerWithArrow.showForIcon(btv) != null;
+        } else if (action == CLOSE) {
+            if (host instanceof AppWidgetResizeFrame) {
+                AbstractFloatingView.closeOpenViews(mContext, /* animate= */ false,
+                        AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME);
+            }
         } else {
             for (ButtonDropTarget dropTarget : mContext.getDropTargetBar().getDropTargets()) {
                 if (dropTarget.supportsAccessibilityDrop(item, host)
@@ -222,6 +241,10 @@
 
     private List<OptionItem> getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
         List<OptionItem> actions = new ArrayList<>();
+        if (host instanceof AppWidgetResizeFrame) {
+            return getSupportedResizeActions(
+                    ((AppWidgetResizeFrame) host).getViewForAccessibility(), info);
+        }
         AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo();
         if (providerInfo == null) {
             return actions;
@@ -496,7 +519,7 @@
         Folder folder = Folder.getOpen(mContext);
         folder.close(true);
         WorkspaceItemInfo info = (WorkspaceItemInfo) item;
-        folder.getInfo().remove(info, false);
+        folder.removeFolderContent(false, info);
 
         final int[] coordinates = new int[2];
         final int screenId = findSpaceOnWorkspace(item, coordinates);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index fafa60b..f60896e 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -181,6 +181,7 @@
     private ScrimView mScrimView;
     private int mHeaderColor;
     private int mBottomSheetBackgroundColor;
+    private float mBottomSheetBackgroundAlpha = 1f;
     private int mTabsProtectionAlpha;
     @Nullable private AllAppsTransitionController mAllAppsTransitionController;
 
@@ -311,7 +312,17 @@
                 0,
                 0 // Bottom left
         };
-        mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim);
+        if (Flags.allAppsBlur()) {
+            int resId = Utilities.isDarkTheme(getContext())
+                    ? android.R.color.system_accent1_800 : android.R.color.system_accent1_100;
+            int layerAbove = ColorUtils.setAlphaComponent(getResources().getColor(resId, null),
+                    (int) (0.4f * 255));
+            int layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.1f * 255));
+            mBottomSheetBackgroundColor = ColorUtils.compositeColors(layerAbove, layerBelow);
+        } else {
+            mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim);
+        }
+        mBottomSheetBackgroundAlpha = Color.alpha(mBottomSheetBackgroundColor) / 255.0f;
         updateBackgroundVisibility(mActivityContext.getDeviceProfile());
         mSearchUiManager.initializeSearch(this);
     }
@@ -1152,7 +1163,7 @@
 
         if (!grid.isVerticalBarLayout() || FeatureFlags.enableResponsiveWorkspace()) {
             int topPadding = grid.allAppsPadding.top;
-            if (isSearchBarFloating() && !grid.isTablet) {
+            if (isSearchBarFloating() && !grid.shouldShowAllAppsOnSheet()) {
                 topPadding += getResources().getDimensionPixelSize(
                         R.dimen.all_apps_additional_top_padding_floating_search);
             }
@@ -1401,7 +1412,7 @@
         // Draw full background panel for tablets.
         if (hasBottomSheet) {
             mHeaderPaint.setColor(mBottomSheetBackgroundColor);
-            mHeaderPaint.setAlpha(255);
+            mHeaderPaint.setAlpha((int) (mBottomSheetBackgroundAlpha * 255));
 
             mTmpRectF.set(
                     leftWithScale,
@@ -1424,6 +1435,10 @@
             return;
         }
 
+        if (hasBottomSheet) {
+            mHeaderPaint.setAlpha((int) (mHeaderPaint.getAlpha() * mBottomSheetBackgroundAlpha));
+        }
+
         // Draw header on background panel
         final float headerBottomNoScale =
                 getHeaderBottom() + getVisibleContainerView().getPaddingTop();
@@ -1455,7 +1470,11 @@
                 mHeaderPaint.setColor(Color.BLUE);
                 mHeaderPaint.setAlpha(255);
             } else {
-                mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
+                float tabAlpha = getAlpha() * mTabsProtectionAlpha;
+                if (hasBottomSheet) {
+                    tabAlpha *= mBottomSheetBackgroundAlpha;
+                }
+                mHeaderPaint.setAlpha((int) tabAlpha);
             }
             float left = 0f;
             float right = canvas.getWidth();
@@ -1507,7 +1526,7 @@
     public int getHeaderBottom() {
         int bottom = (int) getTranslationY() + mHeader.getClipTop();
         if (isSearchBarFloating()) {
-            if (mActivityContext.getDeviceProfile().isTablet) {
+            if (mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) {
                 return bottom + mBottomSheetBackground.getTop();
             }
             return bottom;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4cc31d2..350f763 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -290,7 +290,8 @@
     private void onScaleProgressChanged() {
         final float scaleProgress = mAllAppScale.value;
         SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
-        if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+        if (!mLauncher.getAppsView().isSearching()
+                || !mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
         }
 
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 5f632fe..f223eaa 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -64,7 +64,7 @@
         AllAppsStore.OnUpdateListener {
 
     public static final String TAG = "AlphabeticalAppsList";
-    private static final String PRIVATE_SPACE_PACKAGE = "com.android.privatespace";
+    public static final String PRIVATE_SPACE_PACKAGE = "com.android.privatespace";
 
     private final WorkProfileManager mWorkProviderManager;
 
@@ -436,6 +436,8 @@
                 if (currentItem.itemInfo != null && Objects.equals(
                         currentItem.itemInfo.getTargetPackage(), PRIVATE_SPACE_PACKAGE)) {
                     currentItem.itemInfo.bitmap.creationFlags |= FLAG_NO_BADGE;
+                    currentItem.itemInfo.contentDescription =
+                            mPrivateProviderManager.getPsAppContentDesc();
                     privateSpaceAppIndex = i;
                 }
             }
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 609edd2..1bc1b17 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -142,6 +142,7 @@
     private PrivateSpaceSettingsButton mPrivateSpaceSettingsButton;
     @Nullable
     private ConstraintLayout mFloatingMaskView;
+    private final String mPrivateSpaceAppContentDesc;
     private final String mLockedStateContentDesc;
     private final String mUnLockedStateContentDesc;
 
@@ -157,6 +158,8 @@
         UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext));
         mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize(
                 R.dimen.ps_header_height);
+        mPrivateSpaceAppContentDesc = mAllApps.getContext()
+                .getString(R.string.ps_app_content_description);
         mLockedStateContentDesc = mAllApps.getContext()
                 .getString(R.string.ps_container_lock_button_content_description);
         mUnLockedStateContentDesc = mAllApps.getContext()
@@ -929,6 +932,10 @@
         return mPsHeaderHeight;
     }
 
+    String getPsAppContentDesc() {
+        return mPrivateSpaceAppContentDesc;
+    }
+
     boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
         return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
                 || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 06643d3..c499097 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -28,6 +28,7 @@
 import com.android.launcher3.graphics.ThemeManager;
 import com.android.launcher3.icons.LauncherIcons.IconPool;
 import com.android.launcher3.model.ItemInstallQueue;
+import com.android.launcher3.model.LoaderCursor.LoaderCursorFactory;
 import com.android.launcher3.model.WidgetsFilterDataProvider;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.UserCache;
@@ -87,6 +88,8 @@
     GridCustomizationsProxy getGridCustomizationsProxy();
     WidgetsFilterDataProvider getWidgetsFilterDataProvider();
 
+    LoaderCursorFactory getLoaderCursorFactory();
+
     /** Builder for LauncherBaseAppComponent. */
     interface Builder {
         @BindsInstance Builder appContext(@ApplicationContext Context context);
diff --git a/src/com/android/launcher3/debug/TestEventEmitter.java b/src/com/android/launcher3/debug/TestEventEmitter.java
index ed3b4bb..db69bc2 100644
--- a/src/com/android/launcher3/debug/TestEventEmitter.java
+++ b/src/com/android/launcher3/debug/TestEventEmitter.java
@@ -34,7 +34,9 @@
         RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"),
         WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"),
         SPRING_LOADED_STATE_STARTED("SPRING_LOADED_STATE_STARTED"),
-        SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED");
+        SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"),
+
+        LAUNCHER_STATE_COMPLETED("LAUNCHER_STATE_COMPLETED");
 
         TestEvent(String event) {
         }
diff --git a/src/com/android/launcher3/dot/FolderDotInfo.java b/src/com/android/launcher3/dot/FolderDotInfo.java
index 54800a0..cb91db7 100644
--- a/src/com/android/launcher3/dot/FolderDotInfo.java
+++ b/src/com/android/launcher3/dot/FolderDotInfo.java
@@ -30,6 +30,10 @@
 
     private int mNumNotifications;
 
+    public void reset() {
+        mNumNotifications = 0;
+    }
+
     public void addDotInfo(DotInfo dotToAdd) {
         if (dotToAdd == null) {
             return;
@@ -39,15 +43,6 @@
                 mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT);
     }
 
-    public void subtractDotInfo(DotInfo dotToSubtract) {
-        if (dotToSubtract == null) {
-            return;
-        }
-        mNumNotifications -= dotToSubtract.getNotificationKeys().size();
-        mNumNotifications = Utilities.boundToRange(
-                mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT);
-    }
-
     @Override
     public int getNotificationCount() {
         return mNumNotifications;
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 613b430..415a2c6 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.dragndrop;
 
+import static com.android.launcher3.Flags.removeAppsRefreshOnRightClick;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 
 import android.graphics.Point;
@@ -521,17 +522,21 @@
 
         mDragObject.dragComplete = true;
         if (mIsInPreDrag) {
-            if (dropTarget != null) {
-                dropTarget.onDragExit(mDragObject);
+            if (removeAppsRefreshOnRightClick()) {
+                mDragObject.cancelled = true;
+            } else {
+                if (dropTarget != null) {
+                    dropTarget.onDragExit(mDragObject);
+                }
+                return;
             }
-            return;
         }
 
         // Drop onto the target.
         boolean accepted = false;
         if (dropTarget != null) {
             dropTarget.onDragExit(mDragObject);
-            if (dropTarget.acceptDrop(mDragObject)) {
+            if (!mIsInPreDrag && dropTarget.acceptDrop(mDragObject)) {
                 if (flingAnimation != null) {
                     flingAnimation.run();
                 } else {
@@ -539,9 +544,10 @@
                 }
                 accepted = true;
             }
+
+            final View dropTargetAsView = dropTarget.getDropView();
+            dispatchDropComplete(dropTargetAsView, accepted);
         }
-        final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
-        dispatchDropComplete(dropTargetAsView, accepted);
     }
 
     private DropTarget findDropTarget(final int x, final int y) {
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index 4aa3673..dd433c0 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -15,7 +15,10 @@
  */
 package com.android.launcher3.dragndrop;
 
+import static android.view.View.VISIBLE;
+
 import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
+import static com.android.launcher3.Flags.removeAppsRefreshOnRightClick;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -25,6 +28,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
 import android.view.View;
 
 import androidx.annotation.Nullable;
@@ -33,10 +37,13 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
+import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.TouchUtil;
 import com.android.launcher3.widget.util.WidgetDragScaleUtils;
 
 /**
@@ -47,6 +54,9 @@
     private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
     private final FlingToDeleteHelper mFlingToDeleteHelper;
 
+    /** Whether or not the drag operation is triggered by mouse right click. */
+    private boolean mIsInMouseRightClick = false;
+
     public LauncherDragController(Launcher launcher) {
         super(launcher);
         mFlingToDeleteHelper = new FlingToDeleteHelper(launcher);
@@ -69,6 +79,28 @@
             android.os.Debug.startMethodTracing("Launcher");
         }
 
+        if (removeAppsRefreshOnRightClick() && mIsInMouseRightClick
+                && options.preDragCondition == null
+                && originalView instanceof View v) {
+            options.preDragCondition = new PreDragCondition() {
+
+                @Override
+                public boolean shouldStartDrag(double distanceDragged) {
+                    return false;
+                }
+
+                @Override
+                public void onPreDragStart(DragObject dragObject) {
+                    // Set it to visible so the text of FolderIcon would not flash (avoid it from
+                    // being invisible and then visible)
+                    v.setVisibility(VISIBLE);
+                }
+
+                @Override
+                public void onPreDragEnd(DragObject dragObject, boolean dragStarted) { }
+            };
+        }
+
         mActivity.hideKeyboard();
         AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_DISCOVERY_BOUNCE);
 
@@ -191,7 +223,7 @@
 
     @Override
     protected void exitDrag() {
-        if (!mActivity.isInState(EDIT_MODE)) {
+        if (!mIsInPreDrag && !mActivity.isInState(EDIT_MODE)) {
             mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
         }
     }
@@ -218,4 +250,13 @@
                 dropCoordinates);
         return mActivity.getWorkspace();
     }
+
+    /**
+     * Intercepts touch events from a drag source view.
+     */
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        mIsInMouseRightClick = TouchUtil.isMouseRightClickDownOrMove(ev);
+        return super.onControllerInterceptTouchEvent(ev);
+    }
 }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2803256..967af05 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -19,9 +19,6 @@
 import static android.text.TextUtils.isEmpty;
 
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
@@ -29,6 +26,7 @@
 import static com.android.launcher3.folder.FolderGridOrganizer.createFolderGridOrganizer;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
+import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType;
 import static com.android.launcher3.testing.shared.TestProtocol.FOLDER_OPENED_MESSAGE;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
@@ -95,14 +93,12 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.FolderInfo.FolderListener;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
-import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
@@ -112,6 +108,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
@@ -123,7 +120,7 @@
  * Represents a set of icons chosen by the user or generated by the system.
  */
 public class Folder extends AbstractFloatingView implements ClipPathView, DragSource,
-        View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
+        View.OnLongClickListener, DropTarget, TextView.OnEditorActionListener,
         View.OnFocusChangeListener, DragListener, ExtendedEditText.OnBackKeyListener,
         LauncherBindableItemsContainer {
     private static final String TAG = "Launcher.Folder";
@@ -180,15 +177,6 @@
         return o instanceof ItemInfo info && willAcceptItemType(info.itemType);
     }
 
-    /**
-     * Checks if {@code itemType} is a type that can be placed in folders.
-     */
-    public static boolean willAcceptItemType(int itemType) {
-        return itemType == ITEM_TYPE_APPLICATION
-                || itemType == ITEM_TYPE_DEEP_SHORTCUT
-                || itemType == ITEM_TYPE_APP_PAIR;
-    }
-
     private Alarm mReorderAlarm = new Alarm(Looper.getMainLooper());
     private Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper());
     private Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper());
@@ -244,7 +232,10 @@
     private boolean mIsExternalDrag;
     private boolean mIsDragInProgress = false;
     private boolean mDeleteFolderOnDropCompleted = false;
+
     private boolean mSuppressFolderDeletion = false;
+    private boolean mSuppressContentUpdate = false;
+
     private boolean mItemAddedBackToSelfViaIcon = false;
     private boolean mIsEditingName = false;
 
@@ -386,9 +377,8 @@
 
         // We do not want to get events for the item being removed, as they will get handled
         // when the drop completes
-        try (SuppressInfoChanges s = new SuppressInfoChanges()) {
-            mInfo.remove(dragObject.dragInfo, true);
-        }
+        executeWithContentUpdateSuppressed(() -> removeFolderContent(true, dragObject.dragInfo));
+
         mIsDragInProgress = true;
         mItemAddedBackToSelfViaIcon = false;
     }
@@ -533,16 +523,7 @@
             lp.customPosition = true;
             setLayoutParams(lp);
         }
-        mItemsInvalidated = true;
-        mInfo.addListener(this);
-
-        if (!isEmpty(mInfo.title)) {
-            mFolderName.setText(mInfo.title);
-            mFolderName.setHint(null);
-        } else {
-            mFolderName.setText("");
-            mFolderName.setHint(R.string.folder_hint_text);
-        }
+        reapplyItemInfo();
         // In case any children didn't come across during loading, clean up the folder accordingly
         mFolderIcon.post(() -> {
             if (getItemCount() <= 1) {
@@ -551,6 +532,17 @@
         });
     }
 
+    public void reapplyItemInfo() {
+        mItemsInvalidated = true;
+
+        if (!isEmpty(mInfo.title)) {
+            mFolderName.setText(mInfo.title);
+            mFolderName.setHint(null);
+        } else {
+            mFolderName.setText("");
+            mFolderName.setHint(R.string.folder_hint_text);
+        }
+    }
 
     /**
      * Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
@@ -681,7 +673,6 @@
         if (!shouldAnimateOpen(items)) {
             return;
         }
-
         Folder openFolder = getOpen(mActivityContext);
         closeOpenFolder(openFolder);
 
@@ -955,9 +946,7 @@
 
     @Override
     public boolean acceptDrop(DragObject d) {
-        final ItemInfo item = d.dragInfo;
-        final int itemType = item.itemType;
-        return Folder.willAcceptItemType(itemType);
+        return willAcceptItemType(d.dragInfo.itemType);
     }
 
     public void onDragEnter(DragObject d) {
@@ -1116,13 +1105,14 @@
             View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
                     ? mCurrentDragView : mContent.createNewView(info);
             ArrayList<View> views = getIconsInReadingOrder();
-            info.rank = Utilities.boundToRange(info.rank, 0, views.size());
-            views.add(info.rank, icon);
-            mContent.arrangeChildren(views);
-            mItemsInvalidated = true;
+            if (!views.contains(icon)) {
+                info.rank = Utilities.boundToRange(info.rank, 0, views.size());
+                views.add(info.rank, icon);
+                mContent.arrangeChildren(views);
+                mItemsInvalidated = true;
 
-            try (SuppressInfoChanges s = new SuppressInfoChanges()) {
-                mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */);
+                executeWithContentUpdateSuppressed(
+                        () -> mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */));
             }
         }
 
@@ -1416,9 +1406,7 @@
             rearrangeChildren();
 
             // Temporarily suppress the listener, as we did all the work already here.
-            try (SuppressInfoChanges s = new SuppressInfoChanges()) {
-                mInfo.add(si, mEmptyCellRank, false);
-            }
+            executeWithContentUpdateSuppressed(() -> addFolderContent(si, mEmptyCellRank, false));
 
             // We only need to update the locations if it doesn't get handled in
             // #onDropCompleted.
@@ -1464,37 +1452,66 @@
         }
     }
 
-    @Override
-    public void onAdd(ItemInfo item, int rank) {
-        FolderGridOrganizer verifier = createFolderGridOrganizer(
-                mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
-        verifier.updateRankAndPos(item, rank);
-        mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
-                item.cellY);
-        updateItemLocationsInDatabaseBatch(false);
-
-        if (mContent.areViewsBound()) {
-            mContent.createAndAddViewForRank(item, rank);
-        }
-        mItemsInvalidated = true;
+    /** Add an app or shortcut */
+    public void addFolderContent(ItemInfo item) {
+        addFolderContent(item, mInfo.getContents().size(), true);
     }
 
-    @Override
-    public void onRemove(List<ItemInfo> items) {
-        mItemsInvalidated = true;
-        items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
-        if (mState == STATE_ANIMATING) {
-            mRearrangeOnClose = true;
-        } else {
-            rearrangeChildren();
+    /** Add an app or shortcut for a specified rank */
+    public void addFolderContent(ItemInfo item, int rank, boolean animate) {
+        if (!willAcceptItemType(item.itemType)) {
+            throw new RuntimeException("tried to add an illegal type into a folder");
         }
-        if (getItemCount() <= 1) {
-            if (mIsOpen) {
-                close(true);
-            } else {
-                replaceFolderWithFinalItem();
+
+        rank = Utilities.boundToRange(rank, 0, mInfo.getContents().size());
+        mInfo.getContents().add(rank, item);
+
+        if (!mSuppressContentUpdate) {
+            FolderGridOrganizer verifier = createFolderGridOrganizer(
+                    mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
+            verifier.updateRankAndPos(item, rank);
+            mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0,
+                    item.cellX,
+                    item.cellY);
+            updateItemLocationsInDatabaseBatch(false);
+
+            if (mContent.areViewsBound()) {
+                mContent.createAndAddViewForRank(item, rank);
             }
+            mItemsInvalidated = true;
+            updateTextViewFocus();
         }
+
+        mLauncherDelegate.getModelWriter().notifyItemModified(mInfo);
+        mFolderIcon.onItemsChanged(animate);
+    }
+
+    /** Remove all matching app or shortcut. Does not change the DB. */
+    public void removeFolderContent(boolean animate, ItemInfo... items) {
+        List<ItemInfo> itemArray = Arrays.asList(items);
+        if (mInfo.getContents().removeAll(itemArray)) {
+            mLauncherDelegate.getModelWriter().notifyItemModified(mInfo);
+        }
+
+        if (!mSuppressContentUpdate) {
+            mItemsInvalidated = true;
+            itemArray.forEach(item -> mContent.removeItem(getViewForInfo(item)));
+            if (mState == STATE_ANIMATING) {
+                mRearrangeOnClose = true;
+            } else {
+                rearrangeChildren();
+            }
+            if (getItemCount() <= 1) {
+                if (mIsOpen) {
+                    close(true);
+                } else {
+                    replaceFolderWithFinalItem();
+                }
+            }
+            updateTextViewFocus();
+        }
+
+        mFolderIcon.onItemsChanged(animate);
     }
 
     @VisibleForTesting
@@ -1502,16 +1519,6 @@
         return mContent.iterateOverItems((info, view) -> info == item);
     }
 
-    @Override
-    public void onItemsChanged(boolean animate) {
-        updateTextViewFocus();
-    }
-
-    @Override
-    public void onTitleChanged(CharSequence title) {
-        mFolderName.setText(title);
-    }
-
     /**
      * Utility methods to iterate over items of the view
      */
@@ -1665,18 +1672,14 @@
         }
     };
 
-    /**
-     * Temporary resource held while we don't want to handle info changes
-     */
-    private class SuppressInfoChanges implements AutoCloseable {
-
-        SuppressInfoChanges() {
-            mInfo.removeListener(Folder.this);
-        }
-
-        @Override
-        public void close() {
-            mInfo.addListener(Folder.this);
+    /** Executes the task while suppressing the content update for the folder */
+    private void executeWithContentUpdateSuppressed(Runnable task) {
+        if (mSuppressContentUpdate) {
+            task.run();
+        } else {
+            mSuppressContentUpdate = true;
+            task.run();
+            mSuppressContentUpdate = false;
             updateTextViewFocus();
         }
     }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 0ed8787..1cd9bcc 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS;
+import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -73,7 +74,6 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.FolderInfo.FolderListener;
 import com.android.launcher3.model.data.FolderInfo.LabelState;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemFactory;
@@ -92,7 +92,7 @@
 /**
  * An icon that can appear on in the workspace representing an {@link Folder}.
  */
-public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
+public class FolderIcon extends FrameLayout implements FloatingIconViewCompanion,
         DraggableView, Reorderable {
 
     private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
@@ -127,7 +127,7 @@
 
     private boolean mForceHideDot;
     @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
-    private FolderDotInfo mDotInfo = new FolderDotInfo();
+    private final FolderDotInfo mDotInfo = new FolderDotInfo();
     private DotRenderer mDotRenderer;
     @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
     private DotRenderer.DrawParams mDotParams;
@@ -178,7 +178,6 @@
         folder.bind(folderInfo);
 
         icon.setFolder(folder);
-        folderInfo.addListener(icon);
         return icon;
     }
 
@@ -217,13 +216,7 @@
         icon.mDotRenderer = grid.mDotRendererWorkSpace;
 
         icon.setContentDescription(icon.getAccessiblityTitle(folderInfo.title));
-
-        // Keep the notification dot up to date with the sum of all the content's dots.
-        FolderDotInfo folderDotInfo = new FolderDotInfo();
-        for (ItemInfo si : folderInfo.getContents()) {
-            folderDotInfo.addDotInfo(activity.getDotInfoForItem(si));
-        }
-        icon.setDotInfo(folderDotInfo);
+        icon.updateDotInfo();
 
         icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
 
@@ -264,22 +257,13 @@
     }
 
     private boolean willAcceptItem(ItemInfo item) {
-        final int itemType = item.itemType;
-        return (Folder.willAcceptItemType(itemType) && item != mInfo && !mFolder.isOpen());
+        return (willAcceptItemType(item.itemType) && item != mInfo && !mFolder.isOpen());
     }
 
     public boolean acceptDrop(ItemInfo dragInfo) {
         return !mFolder.isDestroyed() && willAcceptItem(dragInfo);
     }
 
-    public void addItem(ItemInfo item) {
-        mInfo.add(item, true);
-    }
-
-    public void removeItem(ItemInfo item, boolean animate) {
-        mInfo.remove(item, animate);
-    }
-
     public void onDragEnter(ItemInfo dragInfo) {
         if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return;
         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) getLayoutParams();
@@ -308,9 +292,8 @@
     public void performCreateAnimation(final ItemInfo destInfo, final View destView,
             final ItemInfo srcInfo, final DragObject d, Rect dstRect,
             float scaleRelativeToDragLayer) {
-        final DragView srcView = d.dragView;
         prepareCreateAnimation(destView);
-        addItem(destInfo);
+        getFolder().addFolderContent(destInfo);
         // This will animate the first item from it's position as an icon into its
         // position as the first item in the preview
         mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null)
@@ -364,7 +347,7 @@
             boolean itemAdded = false;
             if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
                 List<ItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
-                mInfo.add(item, index, false);
+                getFolder().addFolderContent(item, index, false);
                 mCurrentPreviewItems.clear();
                 mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
 
@@ -380,12 +363,12 @@
                     mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item);
                     itemAdded = true;
                 } else {
-                    removeItem(item, false);
+                    getFolder().removeFolderContent(false, item);
                 }
             }
 
             if (!itemAdded) {
-                mInfo.add(item, index, true);
+                getFolder().addFolderContent(item, index, true);
             }
 
             int[] center = new int[2];
@@ -431,7 +414,7 @@
                 }, DROP_IN_ANIMATION_DURATION);
             });
         } else {
-            addItem(item);
+            getFolder().addFolderContent(item);
         }
     }
 
@@ -500,9 +483,23 @@
         );
     }
 
-    public void setDotInfo(FolderDotInfo dotInfo) {
-        updateDotScale(mDotInfo.hasDot(), dotInfo.hasDot());
-        mDotInfo = dotInfo;
+    /** Keep the notification dot up to date with the sum of all the content's dots. */
+    public void updateDotInfo() {
+        boolean hadDot = mDotInfo.hasDot();
+        mDotInfo.reset();
+        for (ItemInfo si : mInfo.getContents()) {
+            mDotInfo.addDotInfo(mActivity.getDotInfoForItem(si));
+        }
+        boolean isDotted = mDotInfo.hasDot();
+        float newDotScale = isDotted ? 1f : 0f;
+        // Animate when a dot is first added or when it is removed.
+        if ((hadDot ^ isDotted) && isShown()) {
+            animateDotScale(newDotScale);
+        } else {
+            cancelDotScaleAnim();
+            mDotScale = newDotScale;
+            invalidate();
+        }
     }
 
     public ClippedFolderIconLayoutRule getLayoutRule() {
@@ -523,22 +520,6 @@
         }
     }
 
-    /**
-     * Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false
-     * (the dot is being added or removed).
-     */
-    private void updateDotScale(boolean wasDotted, boolean isDotted) {
-        float newDotScale = isDotted ? 1f : 0f;
-        // Animate when a dot is first added or when it is removed.
-        if ((wasDotted ^ isDotted) && isShown()) {
-            animateDotScale(newDotScale);
-        } else {
-            cancelDotScaleAnim();
-            mDotScale = newDotScale;
-            invalidate();
-        }
-    }
-
     private void cancelDotScaleAnim() {
         if (mDotScaleAnim != null) {
             mDotScaleAnim.cancel();
@@ -682,13 +663,6 @@
         return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who);
     }
 
-    @Override
-    public void onItemsChanged(boolean animate) {
-        updatePreviewItems(animate);
-        invalidate();
-        requestLayout();
-    }
-
     private void updatePreviewItems(boolean animate) {
         mPreviewItemManager.updatePreviewItems(animate);
         mCurrentPreviewItems.clear();
@@ -702,31 +676,15 @@
         mPreviewItemManager.updatePreviewItems(itemCheck);
     }
 
-    @Override
-    public void onAdd(ItemInfo item, int rank) {
+    public void onItemsChanged(boolean animate) {
         updatePreviewItems(false);
-        boolean wasDotted = mDotInfo.hasDot();
-        mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item));
-        boolean isDotted = mDotInfo.hasDot();
-        updateDotScale(wasDotted, isDotted);
+        updateDotInfo();
         setContentDescription(getAccessiblityTitle(mInfo.title));
+        updatePreviewItems(animate);
         invalidate();
         requestLayout();
     }
 
-    @Override
-    public void onRemove(List<ItemInfo> items) {
-        updatePreviewItems(false);
-        boolean wasDotted = mDotInfo.hasDot();
-        items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
-        boolean isDotted = mDotInfo.hasDot();
-        updateDotScale(wasDotted, isDotted);
-        setContentDescription(getAccessiblityTitle(mInfo.title));
-        invalidate();
-        requestLayout();
-    }
-
-    @Override
     public void onTitleChanged(CharSequence title) {
         mFolderName.setText(title);
         setContentDescription(getAccessiblityTitle(title));
@@ -762,11 +720,6 @@
         mLongPressHelper.cancelLongPress();
     }
 
-    public void removeListeners() {
-        mInfo.removeListener(this);
-        mInfo.removeListener(mFolder);
-    }
-
     private boolean isInHotseat() {
         return mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
     }
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index bebe1a4..0963421 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -47,6 +47,7 @@
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pageindicators.Direction;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
 import com.android.launcher3.util.Thunk;
@@ -129,6 +130,8 @@
     public void setFolder(Folder folder) {
         mFolder = folder;
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
+        mPageIndicator.setArrowClickListener(direction -> snapToPageImmediately(
+                (Direction.END == direction) ? mCurrentPage + 1 : mCurrentPage - 1));
         initParentViews(folder);
     }
 
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
index 70b9f46..48519ce 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
@@ -113,6 +113,7 @@
     private static final String KEY_SHAPE_OPTIONS = "/shape_options";
     // default_grid is for setting grid and shape to system settings
     private static final String KEY_DEFAULT_GRID = "/default_grid";
+    private static final String SET_SHAPE = "/shape";
 
     private static final String METHOD_GET_PREVIEW = "get_preview";
 
@@ -130,6 +131,7 @@
     private static final int MESSAGE_ID_UPDATE_SHAPE = 2586;
     private static final int MESSAGE_ID_UPDATE_GRID = 7414;
     private static final int MESSAGE_ID_UPDATE_COLOR = 856;
+    private static final int MESSAGE_ID_UPDATE_ICON_THEMED = 311;
 
     // Set of all active previews used to track duplicate memory allocations
     private final Set<PreviewLifecycleObserver> mActivePreviews =
@@ -264,6 +266,12 @@
                 mContext.getContentResolver().notifyChange(uri, null);
                 return 1;
             }
+            case SET_SHAPE:
+                if (Flags.newCustomizationPickerUi()) {
+                    mPrefs.put(PREF_ICON_SHAPE,
+                            requireNonNullElse(values.getAsString(KEY_SHAPE_KEY), ""));
+                }
+                return 1;
             case ICON_THEMED:
             case SET_ICON_THEMED: {
                 mThemeManager.setMonoThemeEnabled(values.getAsBoolean(BOOLEAN_VALUE));
@@ -384,6 +392,12 @@
                         renderer.previewColor(message.getData());
                     }
                     break;
+                case MESSAGE_ID_UPDATE_ICON_THEMED:
+                    if (Flags.newCustomizationPickerUi()) {
+                        Boolean iconThemed = message.getData().getBoolean(BOOLEAN_VALUE);
+                        // TODO Update icon themed in the preview
+                    }
+                    break;
                 default:
                     // Unknown command, destroy lifecycle
                     Log.d(TAG, "Unknown preview command: " + message.what + ", destroying preview");
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index b80238c..e4e4b90 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -80,8 +80,10 @@
 import com.android.launcher3.dagger.LauncherAppModule;
 import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.BaseLauncherBinder.BaseLauncherBinderFactory;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
+import com.android.launcher3.model.LoaderTask.LoaderTaskFactory;
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
@@ -605,6 +607,10 @@
     @Component(modules = LauncherAppModule.class)
     public interface PreviewAppComponent extends LauncherAppComponent {
 
+        LoaderTaskFactory getLoaderTaskFactory();
+        BaseLauncherBinderFactory getBaseLauncherBinderFactory();
+        BgDataModel getDataModel();
+
         /** Builder for NexusLauncherAppComponent. */
         @Component.Builder
         interface Builder extends LauncherAppComponent.Builder {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index d425f03..457d12e 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -21,7 +21,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.launcher3.LauncherPrefs.GRID_NAME;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.graphics.ThemeManager.PREF_ICON_SHAPE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -58,19 +57,21 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.dagger.LauncherComponentProvider;
+import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewAppComponent;
 import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
-import com.android.launcher3.model.BaseLauncherBinder;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDbController;
+import com.android.launcher3.model.UserManagerState;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.widget.LocalColorExtractor;
 import com.android.systemui.shared.Flags;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -177,7 +178,7 @@
 
         ModelDbController mainController =
                 LauncherAppState.getInstance(mContext).getModel().getModelDbController();
-        try (Cursor c = mainController.query(TABLE_NAME,
+        try (Cursor c = mainController.query(
                 new String[] {
                         LauncherSettings.Favorites.APPWIDGET_ID,
                         LauncherSettings.Favorites.SPANX,
@@ -338,38 +339,32 @@
             // Start the migration
             PreviewContext previewContext =
                     new PreviewContext(inflationContext, mGridName, mShapeKey);
+            PreviewAppComponent appComponent =
+                    (PreviewAppComponent) LauncherComponentProvider.get(previewContext);
 
-            BgDataModel bgModel = new BgDataModel();
-            new LoaderTask(
-                    LauncherAppState.getInstance(previewContext),
-                    /* bgAllAppsList= */ null,
-                    bgModel,
-                    LauncherAppState.getInstance(previewContext).getModel().getModelDelegate(),
-                    new BaseLauncherBinder(LauncherAppState.getInstance(previewContext), bgModel,
-                            /* bgAllAppsList= */ null, new Callbacks[0])) {
+            LoaderTask task = appComponent.getLoaderTaskFactory().newLoaderTask(
+                    appComponent.getBaseLauncherBinderFactory().createBinder(new Callbacks[0]),
+                    new UserManagerState());
 
-                @Override
-                public void run() {
-                    InvariantDeviceProfile idp = LauncherAppState.getIDP(previewContext);
-                    DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext);
-                    String query =
-                            LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
-                                    + " or " + LauncherSettings.Favorites.CONTAINER + " = "
-                                    + LauncherSettings.Favorites.CONTAINER_HOTSEAT;
-                    if (deviceProfile.isTwoPanels) {
-                        query += " or " + LauncherSettings.Favorites.SCREEN + " = "
-                                + Workspace.SECOND_SCREEN_ID;
-                    }
-                    loadWorkspace(new ArrayList<>(), query, null, null);
+            InvariantDeviceProfile idp = appComponent.getIDP();
+            DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext);
+            String query =
+                    LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
+                            + " or " + LauncherSettings.Favorites.CONTAINER + " = "
+                            + LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+            if (deviceProfile.isTwoPanels) {
+                query += " or " + LauncherSettings.Favorites.SCREEN + " = "
+                        + Workspace.SECOND_SCREEN_ID;
+            }
 
-                    final SparseArray<Size> spanInfo = getLoadedLauncherWidgetInfo();
-                    MAIN_EXECUTOR.execute(() -> {
-                        renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo,
-                                idp);
-                        mLifeCycleTracker.add(previewContext::onDestroy);
-                    });
-                }
-            }.run();
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap = new HashMap<>();
+            task.loadWorkspaceForPreview(query, widgetProviderInfoMap);
+            final SparseArray<Size> spanInfo = getLoadedLauncherWidgetInfo();
+            MAIN_EXECUTOR.execute(() -> {
+                renderView(previewContext, appComponent.getDataModel(), widgetProviderInfoMap,
+                        spanInfo, idp);
+                mLifeCycleTracker.add(previewContext::onDestroy);
+            });
         } else {
             LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> {
                 if (dataModel != null) {
@@ -420,7 +415,6 @@
             view.setTranslationY((mHeight - scale * view.getHeight()) / 2);
         }
 
-
         if (!Flags.newCustomizationPickerUi()) {
             view.setAlpha(mSkipAnimations ? 1 : 0);
             view.animate().alpha(1)
@@ -477,5 +471,4 @@
             MAIN_EXECUTOR.execute(mLifecycleTracker::executeAllAndDestroy);
         }
     }
-
 }
diff --git a/src/com/android/launcher3/graphics/ShapeDelegate.kt b/src/com/android/launcher3/graphics/ShapeDelegate.kt
index 7c04292..01bfe30 100644
--- a/src/com/android/launcher3/graphics/ShapeDelegate.kt
+++ b/src/com/android/launcher3/graphics/ShapeDelegate.kt
@@ -18,6 +18,7 @@
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
+import android.animation.ValueAnimator.AnimatorUpdateListener
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Matrix
@@ -41,7 +42,6 @@
 import androidx.graphics.shapes.rectangle
 import androidx.graphics.shapes.toPath
 import androidx.graphics.shapes.transformed
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider
 import com.android.launcher3.icons.GraphicsUtils
 import com.android.launcher3.views.ClipPathView
 
@@ -127,16 +127,20 @@
             endRadius: Float,
             isReversed: Boolean,
         ): ValueAnimator where T : View, T : ClipPathView {
-            return object :
-                    RoundedRectRevealOutlineProvider(
-                        (startRect.width() / 2f) * radiusRatio,
-                        endRadius,
-                        startRect,
-                        endRect,
-                    ) {
-                    override fun shouldRemoveElevationDuringAnimation() = true
-                }
-                .createRevealAnimator(target, isReversed)
+            val startRadius = (startRect.width() / 2f) * radiusRatio
+            return ClipAnimBuilder(target) { progress, path ->
+                val radius = (1 - progress) * startRadius + progress * endRadius
+                path.addRoundRect(
+                    (1 - progress) * startRect.left + progress * endRect.left,
+                    (1 - progress) * startRect.top + progress * endRect.top,
+                    (1 - progress) * startRect.right + progress * endRect.right,
+                    (1 - progress) * startRect.bottom + progress * endRect.bottom,
+                    radius,
+                    radius,
+                    Path.Direction.CW,
+                )
+            }
+                .toAnim(isReversed)
         }
 
         override fun equals(other: Any?) =
@@ -220,40 +224,46 @@
                         ),
                 )
 
-            val va =
-                if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f)
-            va.addListener(
-                object : AnimatorListenerAdapter() {
-                    private var oldOutlineProvider: ViewOutlineProvider? = null
-
-                    override fun onAnimationStart(animation: Animator) {
-                        target.apply {
-                            oldOutlineProvider = outlineProvider
-                            outlineProvider = null
-                            translationZ = -target.elevation
-                        }
-                    }
-
-                    override fun onAnimationEnd(animation: Animator) {
-                        target.apply {
-                            translationZ = 0f
-                            setClipPath(null)
-                            outlineProvider = oldOutlineProvider
-                        }
-                    }
-                }
-            )
-
-            val path = Path()
-            va.addUpdateListener { anim: ValueAnimator ->
-                path.reset()
-                morph.toPath(anim.animatedValue as Float, path)
-                target.setClipPath(path)
-            }
-            return va
+            return ClipAnimBuilder(target, morph::toPath).toAnim(isReversed)
         }
     }
 
+    private class ClipAnimBuilder<T>(val target: T, val pathProvider: (Float, Path) -> Unit) :
+        AnimatorListenerAdapter(), AnimatorUpdateListener where T : View, T : ClipPathView {
+
+        private var oldOutlineProvider: ViewOutlineProvider? = null
+        val path = Path()
+
+        override fun onAnimationStart(animation: Animator) {
+            target.apply {
+                oldOutlineProvider = outlineProvider
+                outlineProvider = null
+                translationZ = -target.elevation
+            }
+        }
+
+        override fun onAnimationEnd(animation: Animator) {
+            target.apply {
+                translationZ = 0f
+                setClipPath(null)
+                outlineProvider = oldOutlineProvider
+            }
+        }
+
+        override fun onAnimationUpdate(anim: ValueAnimator) {
+            path.reset()
+            pathProvider.invoke(anim.animatedValue as Float, path)
+            target.setClipPath(path)
+        }
+
+        fun toAnim(isReversed: Boolean) =
+            (if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f))
+                .also {
+                    it.addListener(this)
+                    it.addUpdateListener(this)
+                }
+    }
+
     companion object {
 
         const val TAG = "IconShape"
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 45ed489..44d2e26 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -166,6 +166,9 @@
         @UiEvent(doc = "User tapped or long pressed on settings icon inside launcher settings.")
         LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS(463),
 
+        @UiEvent(doc = "User tapped or long pressed on apps icon inside launcher settings.")
+        LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS(2204),
+
         @UiEvent(doc = "User tapped or long pressed on widget tray icon inside launcher settings.")
         LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS(464),
 
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ddbbdc7..dfba4bb 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -66,13 +66,6 @@
 
     /**
      * @param itemList items to add on the workspace
-     */
-    public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList) {
-        this(itemList, new WorkspaceItemSpaceFinder());
-    }
-
-    /**
-     * @param itemList items to add on the workspace
      * @param itemSpaceFinder inject WorkspaceItemSpaceFinder dependency for testing
      */
     public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList,
@@ -91,7 +84,7 @@
 
         final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
         final IntArray addedWorkspaceScreensFinal = new IntArray();
-        final Context context = taskController.getApp().getContext();
+        final Context context = taskController.getContext();
 
         synchronized (dataModel) {
             IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
@@ -133,7 +126,7 @@
 
             for (ItemInfo item : filteredItems) {
                 // Find appropriate space for the item.
-                int[] coords = mItemSpaceFinder.findSpaceForItem(taskController.getApp(), dataModel,
+                int[] coords = mItemSpaceFinder.findSpaceForItem(
                         workspaceScreens, addedWorkspaceScreensFinal, item.spanX, item.spanY);
                 int screenId = coords[0];
 
@@ -192,7 +185,7 @@
                             continue;
                         }
 
-                        IconCache cache = taskController.getApp().getIconCache();
+                        IconCache cache = taskController.getIconCache();
                         WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
                         wii.title = "";
                         wii.bitmap = cache.getDefaultIcon(item.user);
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 98f9afd..2311239 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -34,6 +34,7 @@
 
 import com.android.launcher3.AppFilter;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
@@ -53,11 +54,13 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
+import javax.inject.Inject;
+
 
 /**
  * Stores the list of all applications for the all apps view.
  */
-@SuppressWarnings("NewApi")
+@LauncherAppSingleton
 public class AllAppsList {
 
     private static final String TAG = "AllAppsList";
@@ -70,10 +73,10 @@
     public final ArrayList<AppInfo> data = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER);
 
     @NonNull
-    private IconCache mIconCache;
+    private final IconCache mIconCache;
 
     @NonNull
-    private AppFilter mAppFilter;
+    private final AppFilter mAppFilter;
 
     private boolean mDataChanged = false;
     private Consumer<AppInfo> mRemoveListener = NO_OP_CONSUMER;
@@ -92,6 +95,7 @@
     /**
      * Boring constructor.
      */
+    @Inject
     public AllAppsList(IconCache iconCache, AppFilter appFilter) {
         mIconCache = iconCache;
         mAppFilter = appFilter;
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 262bf67..c4bbae4 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.content.Context;
 import android.os.Trace;
 import android.util.Log;
 import android.util.Pair;
@@ -34,11 +35,12 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherModel.CallbackTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.ApplicationContext;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.AppInfo;
@@ -55,6 +57,10 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -76,7 +82,9 @@
 
     protected final LooperExecutor mUiExecutor;
 
-    protected final LauncherAppState mApp;
+    private final Context mContext;
+    private final InvariantDeviceProfile mIDP;
+    private final LauncherModel mModel;
     protected final BgDataModel mBgDataModel;
     private final AllAppsList mBgAllAppsList;
 
@@ -84,10 +92,18 @@
 
     private int mMyBindingId;
 
-    public BaseLauncherBinder(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacksList) {
+    @AssistedInject
+    public BaseLauncherBinder(
+            @ApplicationContext Context context,
+            InvariantDeviceProfile idp,
+            LauncherModel model,
+            BgDataModel dataModel,
+            AllAppsList allAppsList,
+            @Assisted Callbacks[] callbacksList) {
         mUiExecutor = MAIN_EXECUTOR;
-        mApp = app;
+        mContext = context;
+        mIDP = idp;
+        mModel = model;
         mBgDataModel = dataModel;
         mBgAllAppsList = allAppsList;
         mCallbacksList = callbacksList;
@@ -110,15 +126,14 @@
                 mBgDataModel.extraItems.forEach(extraItems::add);
                 if (incrementBindId) {
                     mBgDataModel.lastBindId++;
-                    mBgDataModel.lastLoadId = mApp.getModel().getLastLoadId();
+                    mBgDataModel.lastLoadId = mModel.getLastLoadId();
                 }
                 mMyBindingId = mBgDataModel.lastBindId;
                 workspaceItemCount = mBgDataModel.itemsIdMap.size();
             }
 
             for (Callbacks cb : mCallbacksList) {
-                new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId,
-                        itemsIdMap, extraItems, orderedScreenIds)
+                new UnifiedWorkspaceBinder(cb, itemsIdMap, extraItems, orderedScreenIds)
                         .bind(isBindSync, workspaceItemCount);
             }
         } finally {
@@ -162,9 +177,8 @@
         if (!WIDGETS_ENABLED) {
             return;
         }
-        List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mApp.getContext())
+        List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mContext)
                 .build(mBgDataModel.widgetsModel.getWidgetsByPackageItemForPicker());
-
         executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
     }
 
@@ -181,10 +195,9 @@
     /**
      * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
      */
-    protected void sortWorkspaceItemsSpatially(InvariantDeviceProfile profile,
-            ArrayList<ItemInfo> workspaceItems) {
-        final int screenCols = profile.numColumns;
-        final int screenCellCount = profile.numColumns * profile.numRows;
+    protected void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
+        final int screenCols = mIDP.numColumns;
+        final int screenCellCount = mIDP.numColumns * mIDP.numRows;
         Collections.sort(workspaceItems, (lhs, rhs) -> {
             if (lhs.container == rhs.container) {
                 // Within containers, order by their spatial position in that container
@@ -240,30 +253,18 @@
 
     private class UnifiedWorkspaceBinder {
 
-        private final Executor mUiExecutor;
         private final Callbacks mCallbacks;
 
-        private final LauncherAppState mApp;
-        private final BgDataModel mBgDataModel;
-
-        private final int mMyBindingId;
         private final IntSparseArrayMap<ItemInfo> mItemIdMap;
         private final IntArray mOrderedScreenIds;
         private final ArrayList<FixedContainerItems> mExtraItems;
 
-        UnifiedWorkspaceBinder(Callbacks callbacks,
-                Executor uiExecutor,
-                LauncherAppState app,
-                BgDataModel bgDataModel,
-                int myBindingId,
+        UnifiedWorkspaceBinder(
+                Callbacks callbacks,
                 IntSparseArrayMap<ItemInfo> itemIdMap,
                 ArrayList<FixedContainerItems> extraItems,
                 IntArray orderedScreenIds) {
             mCallbacks = callbacks;
-            mUiExecutor = uiExecutor;
-            mApp = app;
-            mBgDataModel = bgDataModel;
-            mMyBindingId = myBindingId;
             mItemIdMap = itemIdMap;
             mExtraItems = extraItems;
             mOrderedScreenIds = orderedScreenIds;
@@ -289,9 +290,8 @@
                     (WIDGET_FILTER.test(item) ? otherAppWidgets : otherWorkspaceItems).add(item);
                 }
             });
-            final InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile();
-            sortWorkspaceItemsSpatially(idp, currentWorkspaceItems);
-            sortWorkspaceItemsSpatially(idp, otherWorkspaceItems);
+            sortWorkspaceItemsSpatially(currentWorkspaceItems);
+            sortWorkspaceItemsSpatially(otherWorkspaceItems);
 
             // Tell the workspace that we're about to start binding items
             executeCallbacksTask(c -> {
@@ -352,7 +352,7 @@
             executeCallbacksTask(c -> c.bindStringCache(cacheClone), pendingExecutor);
 
             executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
-            pendingExecutor.execute(() -> ItemInstallQueue.INSTANCE.get(mApp.getContext())
+            pendingExecutor.execute(() -> ItemInstallQueue.INSTANCE.get(mContext)
                     .resumeModelPush(FLAG_LOADER_RUNNING));
         }
 
@@ -367,8 +367,8 @@
                 return;
             }
 
-            ModelWriter writer = mApp.getModel()
-                    .getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null);
+            ModelWriter writer = mModel.getWriter(
+                    false /* verifyChanges */, CellPosMapper.DEFAULT, null);
             List<Pair<ItemInfo, View>> bindItems = items.stream()
                     .map(i -> Pair.create(i, inflater.inflateItem(i, writer, null)))
                     .collect(Collectors.toList());
@@ -398,4 +398,9 @@
             });
         }
     }
+
+    @AssistedFactory
+    public interface BaseLauncherBinderFactory {
+        BaseLauncherBinder createBinder(Callbacks[] callbacks);
+    }
 }
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index d9eccaf..ea9f36c 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.BuildConfig;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.CollectionInfo;
@@ -79,9 +80,15 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import javax.inject.Inject;
+
 /**
  * All the data stored in-memory and managed by the LauncherModel
+ *
+ * All the static data should be accessed on the background thread, A lock should be acquired on
+ * this object when accessing any data from this model.
  */
+@LauncherAppSingleton
 public class BgDataModel {
 
     private static final String TAG = "BgDataModel";
@@ -105,7 +112,7 @@
     /**
      * Entire list of widgets.
      */
-    public final WidgetsModel widgetsModel = new WidgetsModel();
+    public final WidgetsModel widgetsModel;
 
     /**
      * Cache for strings used in launcher
@@ -124,6 +131,11 @@
     public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN
             && !enableSmartspaceRemovalToggle();
 
+    @Inject
+    public BgDataModel(WidgetsModel widgetsModel) {
+        this.widgetsModel = widgetsModel;
+    }
+
     /**
      * Clears all the data
      */
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 48934e2..f740b49 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -59,7 +59,7 @@
     @Override
     public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
             @NonNull AllAppsList apps) {
-        IconCache iconCache = taskController.getApp().getIconCache();
+        IconCache iconCache = taskController.getIconCache();
         ArrayList<ItemInfo> updatedItems = new ArrayList<>();
 
         synchronized (dataModel) {
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index f443f81..829e0fe 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -45,9 +45,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -76,9 +76,9 @@
 
     private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken";
 
-    private final HashMap<PackageUserKey, SessionInfo> mSessionInfoForPackage;
+    private final Map<PackageUserKey, SessionInfo> mSessionInfoForPackage;
 
-    public FirstScreenBroadcast(HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage) {
+    public FirstScreenBroadcast(Map<PackageUserKey, SessionInfo> sessionInfoForPackage) {
         mSessionInfoForPackage = sessionInfoForPackage;
     }
 
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index bd8c36b..efe6157 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
 import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
@@ -45,13 +44,14 @@
 
 import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.ApplicationContext;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.AppInfo;
@@ -70,6 +70,10 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.UserIconInfo;
 
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
 import java.net.URISyntaxException;
 import java.security.InvalidParameterException;
 
@@ -82,8 +86,8 @@
 
     private final LongSparseArray<UserHandle> allUsers;
 
-    private final LauncherAppState mApp;
     private final Context mContext;
+    private final LauncherModel mModel;
     private final PackageManagerHelper mPmHelper;
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mIDP;
@@ -130,17 +134,24 @@
     public int itemType;
     public int restoreFlag;
 
-    public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState,
-            PackageManagerHelper pmHelper,
-            @Nullable LauncherRestoreEventLogger restoreEventLogger) {
+    @AssistedInject
+    public LoaderCursor(
+            @Assisted Cursor cursor,
+            @Assisted UserManagerState userManagerState,
+            @Assisted @Nullable LauncherRestoreEventLogger restoreEventLogger,
+            @ApplicationContext Context context,
+            IconCache iconCache,
+            InvariantDeviceProfile idp,
+            LauncherModel model,
+            PackageManagerHelper pmHelper) {
         super(cursor);
-
-        mApp = app;
-        allUsers = userManagerState.allUsers;
-        mContext = app.getContext();
-        mIconCache = app.getIconCache();
+        mContext = context;
+        mIconCache = iconCache;
+        mIDP = idp;
+        mModel = model;
         mPmHelper = pmHelper;
-        mIDP = app.getInvariantDeviceProfile();
+
+        allUsers = userManagerState.allUsers;
         mRestoreEventLogger = restoreEventLogger;
 
         // Init column indices
@@ -432,7 +443,7 @@
      */
     public ContentWriter updater() {
        return new ContentWriter(mContext, new ContentWriter.CommitParams(
-               mApp.getModel().getModelDbController(),
+               mModel.getModelDbController(),
                BaseColumns._ID + "= ?", new String[]{Integer.toString(id)}));
     }
 
@@ -454,7 +465,7 @@
     public boolean commitDeleted() {
         if (mItemsToRemove.size() > 0) {
             // Remove dead items
-            mApp.getModel().getModelDbController().delete(TABLE_NAME,
+            mModel.getModelDbController().delete(
                     Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null);
             return true;
         }
@@ -480,7 +491,7 @@
             // Update restored items that no longer require special handling
             ContentValues values = new ContentValues();
             values.put(Favorites.RESTORED, 0);
-            mApp.getModel().getModelDbController().update(TABLE_NAME, values,
+            mModel.getModelDbController().update(values,
                     Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null);
         }
         if (mRestoreEventLogger != null) {
@@ -645,4 +656,12 @@
             return false;
         }
     }
+
+    @AssistedFactory
+    public interface LoaderCursorFactory {
+
+        LoaderCursor createLoaderCursor(Cursor cursor,
+                UserManagerState userManagerState,
+                @Nullable LauncherRestoreEventLogger restoreEventLogger);
+    }
 }
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index fb1ebaf..78e5d89 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -23,7 +23,6 @@
 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.DESKTOP_ICON_FLAG;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.icons.CacheableShortcutInfo.convertShortcutsToCacheableShortcuts;
 import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
@@ -53,7 +52,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.util.ArrayMap;
 import android.util.Log;
 import android.util.LongSparseArray;
 
@@ -63,13 +61,14 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.Flags;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.ApplicationContext;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderGridOrganizer;
 import com.android.launcher3.folder.FolderNameInfos;
@@ -82,6 +81,7 @@
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
 import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
 import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.model.LoaderCursor.LoaderCursorFactory;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
@@ -106,6 +106,10 @@
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.widget.WidgetInflater;
 
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -117,6 +121,8 @@
 import java.util.Set;
 import java.util.concurrent.CancellationException;
 
+import javax.inject.Named;
+
 /**
  * Runnable for the thread that loads the contents of the launcher:
  *   - workspace icons
@@ -131,10 +137,14 @@
 
     private static final boolean DEBUG = true;
 
-    @NonNull
-    protected final LauncherAppState mApp;
+    private final Context mContext;
+    private final LauncherModel mModel;
+    private final InvariantDeviceProfile mIDP;
+    private final boolean mIsSafeModeEnabled;
     private final AllAppsList mBgAllAppsList;
     protected final BgDataModel mBgDataModel;
+    private final LoaderCursorFactory mLoaderCursorFactory;
+
     private final ModelDelegate mModelDelegate;
     private boolean mIsRestoreFromBackup;
 
@@ -152,7 +162,6 @@
     private final IconCache mIconCache;
 
     private final UserManagerState mUserManagerState;
-    protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
     private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts;
     private HashMap<PackageUserKey, SessionInfo> mInstallingPkgsCached;
 
@@ -164,26 +173,36 @@
     private boolean mItemsDeleted = false;
     private String mDbName;
 
-    public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
-            ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder) {
-        this(app, bgAllAppsList, bgModel, modelDelegate, launcherBinder, new UserManagerState());
-    }
-
-    @VisibleForTesting
-    LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
-            ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder,
-            UserManagerState userManagerState) {
-        mApp = app;
+    @AssistedInject
+    LoaderTask(
+            @ApplicationContext Context context,
+            InvariantDeviceProfile idp,
+            LauncherModel model,
+            UserCache userCache,
+            PackageManagerHelper pmHelper,
+            InstallSessionHelper sessionHelper,
+            IconCache iconCache,
+            AllAppsList bgAllAppsList,
+            BgDataModel bgModel,
+            LoaderCursorFactory loaderCursorFactory,
+            @Named("SAFE_MODE") boolean isSafeModeEnabled,
+            @Assisted @NonNull BaseLauncherBinder launcherBinder,
+            @Assisted UserManagerState userManagerState) {
+        mContext = context;
+        mIDP = idp;
+        mModel = model;
+        mIsSafeModeEnabled = isSafeModeEnabled;
         mBgAllAppsList = bgAllAppsList;
         mBgDataModel = bgModel;
-        mModelDelegate = modelDelegate;
+        mModelDelegate = model.getModelDelegate();
         mLauncherBinder = launcherBinder;
-        mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
-        mUserManager = mApp.getContext().getSystemService(UserManager.class);
-        mUserCache = UserCache.INSTANCE.get(mApp.getContext());
-        mPmHelper = PackageManagerHelper.INSTANCE.get(mApp.getContext());
-        mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
-        mIconCache = mApp.getIconCache();
+        mLoaderCursorFactory = loaderCursorFactory;
+        mLauncherApps = mContext.getSystemService(LauncherApps.class);
+        mUserManager = mContext.getSystemService(UserManager.class);
+        mUserCache = userCache;
+        mPmHelper = pmHelper;
+        mSessionHelper = sessionHelper;
+        mIconCache = iconCache;
         mUserManagerState = userManagerState;
         mInstallingPkgsCached = null;
     }
@@ -215,7 +234,7 @@
                         .filter(currentScreenContentFilter(firstScreens))
                         .toList();
         final int disableArchivingLauncherBroadcast = Settings.Secure.getInt(
-                mApp.getContext().getContentResolver(),
+                mContext.getContentResolver(),
                 "disable_launcher_broadcast_installed_apps",
                 /* default */ 0);
         boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
@@ -230,10 +249,10 @@
                             mBgDataModel.itemsIdMap.stream().filter(WIDGET_FILTER).toList()
                     );
             logASplit("Sending first screen broadcast with additional archiving Extras");
-            FirstScreenBroadcastHelper.sendBroadcastsForModels(mApp.getContext(), broadcastModels);
+            FirstScreenBroadcastHelper.sendBroadcastsForModels(mContext, broadcastModels);
         } else {
             logASplit("Sending first screen broadcast");
-            mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
+            mFirstScreenBroadcast.sendBroadcasts(mContext, firstScreenItems);
         }
     }
 
@@ -249,16 +268,14 @@
         MODEL_EXECUTOR.elevatePriority(CALLER_LOADER_TASK);
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
         mIsRestoreFromBackup =
-                LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
+                LauncherPrefs.get(mContext).get(IS_FIRST_LOAD_AFTER_RESTORE);
         LauncherRestoreEventLogger restoreEventLogger = null;
         if (enableLauncherBrMetricsFixed()) {
-            restoreEventLogger = LauncherRestoreEventLogger.Companion
-                    .newInstance(mApp.getContext());
+            restoreEventLogger = LauncherRestoreEventLogger.Companion.newInstance(mContext);
         }
-        try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
-
+        try (LauncherModel.LoaderTransaction transaction = mModel.beginLoader(this)) {
             List<CacheableShortcutInfo> allShortcuts = new ArrayList<>();
-            loadWorkspace(allShortcuts, "", memoryLogger, restoreEventLogger);
+            loadWorkspace(allShortcuts, "", new HashMap<>(), memoryLogger, restoreEventLogger);
 
             // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
             // sanitizeData should not be invoked if the workspace is loaded from a db different
@@ -267,7 +284,7 @@
             // TODO(b/384731096): Write Unit Test to make sure sanitizeWidgetsShortcutsAndPackages
             //  actually re-pins shortcuts that are in model but not in ShortcutManager, if possible
             //  after a simulated restore.
-            if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
+            if (Objects.equals(mIDP.dbFile, mDbName)) {
                 verifyNotStopped();
                 sanitizeFolders(mItemsDeleted);
                 sanitizeAppPairs();
@@ -307,13 +324,13 @@
             setIgnorePackages(updateHandler);
             updateHandler.updateIcons(allActivityList,
                     LauncherActivityCachingLogic.INSTANCE,
-                    mApp.getModel()::onPackageIconsUpdated);
+                    mModel::onPackageIconsUpdated);
             logASplit("update AllApps icon cache finished");
 
             verifyNotStopped();
             logASplit("saving all shortcuts in icon cache");
             updateHandler.updateIcons(allShortcuts, CacheableShortcutCachingLogic.INSTANCE,
-                    mApp.getModel()::onPackageIconsUpdated);
+                    mModel::onPackageIconsUpdated);
 
             // Take a break
             waitForIdle();
@@ -342,14 +359,14 @@
 
             // fourth step
             WidgetsModel widgetsModel = mBgDataModel.widgetsModel;
-            List<CachedObject> allWidgetsList = widgetsModel.update(mApp, /*packageUser=*/null);
+            List<CachedObject> allWidgetsList = widgetsModel.update(/*packageUser=*/null);
             logASplit("load widgets finished");
 
             verifyNotStopped();
             mLauncherBinder.bindWidgets();
             logASplit("bindWidgets finished");
             verifyNotStopped();
-            LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
+            LauncherPrefs prefs = LauncherPrefs.get(mContext);
 
             if (enableSmartspaceAsAWidget() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
                 mLauncherBinder.bindSmartspaceWidget();
@@ -366,7 +383,7 @@
             logASplit("saving all widgets in icon cache");
             updateHandler.updateIcons(allWidgetsList,
                     CachedObjectCachingLogic.INSTANCE,
-                    mApp.getModel()::onWidgetLabelsUpdated);
+                    mModel::onWidgetLabelsUpdated);
 
             // fifth step
             loadFolderNames();
@@ -380,7 +397,7 @@
             memoryLogger.clearLogs();
             if (mIsRestoreFromBackup) {
                 mIsRestoreFromBackup = false;
-                LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
+                LauncherPrefs.get(mContext).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
                 if (restoreEventLogger != null) {
                     restoreEventLogger.reportLauncherRestoreResults();
                 }
@@ -402,35 +419,42 @@
         this.notify();
     }
 
-    protected void loadWorkspace(
+    public void loadWorkspaceForPreview(String selection,
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
+        loadWorkspace(new ArrayList<>(), selection, widgetProviderInfoMap, null, null);
+    }
+
+    private void loadWorkspace(
             List<CacheableShortcutInfo> allDeepShortcuts,
             String selection,
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
             @Nullable LoaderMemoryLogger memoryLogger,
             @Nullable LauncherRestoreEventLogger restoreEventLogger
     ) {
         Trace.beginSection("LoadWorkspace");
         try {
-            loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger, restoreEventLogger);
+            loadWorkspaceImpl(allDeepShortcuts, selection, widgetProviderInfoMap,
+                    memoryLogger, restoreEventLogger);
         } finally {
             Trace.endSection();
         }
         logASplit("loadWorkspace finished");
 
         mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
-                && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(
-                mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
+                && (!enableSmartspaceRemovalToggle()
+                || LauncherPrefs.getPrefs(mContext).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
     }
 
     private void loadWorkspaceImpl(
             List<CacheableShortcutInfo> allDeepShortcuts,
             String selection,
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
             @Nullable LoaderMemoryLogger memoryLogger,
             @Nullable LauncherRestoreEventLogger restoreEventLogger) {
-        final Context context = mApp.getContext();
         final boolean isSdCardReady = Utilities.isBootCompleted();
-        final WidgetInflater widgetInflater = new WidgetInflater(context);
+        final WidgetInflater widgetInflater = new WidgetInflater(mContext, mIsSafeModeEnabled);
 
-        ModelDbController dbController = mApp.getModel().getModelDbController();
+        ModelDbController dbController = mModel.getModelDbController();
         if (Flags.gridMigrationRefactor()) {
             try {
                 dbController.attemptMigrateDb(restoreEventLogger, mModelDelegate);
@@ -452,28 +476,29 @@
             if (Flags.enableSupportForArchiving()) {
                 mInstallingPkgsCached = installingPkgs;
             }
-            installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
+            installingPkgs.forEach(mIconCache::updateSessionCache);
             FileLog.d(TAG, "loadWorkspace: Packages with active install/update sessions: "
                     + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
 
             mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
 
             mShortcutKeyToPinnedShortcuts = new HashMap<>();
-            final LoaderCursor c = new LoaderCursor(
-                    dbController.query(TABLE_NAME, null, selection, null, null),
-                    mApp, mUserManagerState, mPmHelper,
+            final LoaderCursor c = mLoaderCursorFactory.createLoaderCursor(
+                    dbController.query(null, selection, null, null),
+                    mUserManagerState,
                     mIsRestoreFromBackup ? restoreEventLogger : null);
             final Bundle extras = c.getExtras();
             mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME);
             try {
                 final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
-                queryPinnedShortcutsForUnlockedUsers(context, unlockedUsers);
+                queryPinnedShortcutsForUnlockedUsers(mContext, unlockedUsers);
 
                 mWorkspaceIconRequestInfos = new ArrayList<>();
                 WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger,
                         mUserCache, mUserManagerState, mLauncherApps, mPendingPackages,
-                        mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel,
-                        mWidgetProvidersMap, installingPkgs, isSdCardReady,
+                        mShortcutKeyToPinnedShortcuts, mContext, mIDP, mIconCache,
+                        mIsSafeModeEnabled, mBgDataModel,
+                        widgetProviderInfoMap, installingPkgs, isSdCardReady,
                         widgetInflater, mPmHelper, mWorkspaceIconRequestInfos, unlockedUsers,
                         allDeepShortcuts);
 
@@ -577,7 +602,7 @@
     @WorkerThread
     private void processFolderItems() {
         // Sort the folder items, update ranks, and make sure all preview items are high res.
-        List<FolderGridOrganizer> verifiers = mApp.getInvariantDeviceProfile().supportedProfiles
+        List<FolderGridOrganizer> verifiers = mIDP.supportedProfiles
                 .stream().map(FolderGridOrganizer::createFolderGridOrganizer).toList();
         for (ItemInfo itemInfo : mBgDataModel.itemsIdMap) {
             if (!(itemInfo instanceof FolderInfo folder)) {
@@ -617,7 +642,7 @@
                 if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
                     logASplit("tryLoadWorkspaceIconsInBulk: default icon found for "
                             + wai.getTargetComponent() + ", will attempt to load from iconBlob");
-                    iconRequestInfo.loadIconFromDbBlob(mApp.getContext());
+                    iconRequestInfo.loadIconFromDbBlob(mContext);
                 }
             }
         } finally {
@@ -649,7 +674,7 @@
     private void sanitizeFolders(boolean itemsDeleted) {
         if (itemsDeleted) {
             // Remove any empty folder
-            IntArray deletedFolderIds = mApp.getModel().getModelDbController().deleteEmptyFolders();
+            IntArray deletedFolderIds = mModel.getModelDbController().deleteEmptyFolders();
             synchronized (mBgDataModel) {
                 for (int folderId : deletedFolderIds) {
                     mBgDataModel.itemsIdMap.remove(folderId);
@@ -660,8 +685,8 @@
 
     /** Cleans up app pairs if they don't have the right number of member apps (2). */
     private void sanitizeAppPairs() {
-        IntArray deletedAppPairIds = mApp.getModel().getModelDbController().deleteBadAppPairs();
-        IntArray deletedAppIds = mApp.getModel().getModelDbController().deleteUnparentedApps();
+        IntArray deletedAppPairIds = mModel.getModelDbController().deleteBadAppPairs();
+        IntArray deletedAppIds = mModel.getModelDbController().deleteUnparentedApps();
 
         IntArray deleted = new IntArray();
         deleted.addAll(deletedAppPairIds);
@@ -675,17 +700,15 @@
     }
 
     private void sanitizeWidgetsShortcutsAndPackages() {
-        Context context = mApp.getContext();
-
         // Remove any ghost widgets
-        mApp.getModel().getModelDbController().removeGhostWidgets();
+        mModel.getModelDbController().removeGhostWidgets();
 
         // Update pinned state of model shortcuts
-        mBgDataModel.updateShortcutPinnedState(context);
+        mBgDataModel.updateShortcutPinnedState(mContext);
 
         if (!Utilities.isBootCompleted() && !mPendingPackages.isEmpty()) {
-            context.registerReceiver(
-                    new SdCardAvailableReceiver(mApp, mPendingPackages),
+            mContext.registerReceiver(
+                    new SdCardAvailableReceiver(mContext, mModel, mPendingPackages),
                     new IntentFilter(Intent.ACTION_BOOT_COMPLETED),
                     null,
                     MODEL_EXECUTOR.getHandler());
@@ -722,7 +745,7 @@
             for (int i = 0; i < apps.size(); i++) {
                 LauncherActivityInfo app = apps.get(i);
                 AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user),
-                        ApiWrapper.INSTANCE.get(mApp.getContext()), mPmHelper, quietMode);
+                        ApiWrapper.INSTANCE.get(mContext), 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.
@@ -751,7 +774,7 @@
             for (PackageInstaller.SessionInfo info :
                     mSessionHelper.getAllVerifiedSessions()) {
                 AppInfo promiseAppInfo = mBgAllAppsList.addPromiseApp(
-                        mApp.getContext(),
+                        mContext,
                         PackageInstallInfo.fromInstallingState(info),
                         false);
 
@@ -776,7 +799,7 @@
                                 + appInfo.getTargetComponent()
                                 + ", will attempt to load from iconBlob: "
                                 + Arrays.toString(iconRequestInfo.iconBlob));
-                        iconRequestInfo.loadIconFromDbBlob(mApp.getContext());
+                        iconRequestInfo.loadIconFromDbBlob(mContext);
                     }
                 }
             }
@@ -794,9 +817,9 @@
                     mUserManagerState.isAnyProfileQuietModeEnabled());
         }
         mBgAllAppsList.setFlags(FLAG_HAS_SHORTCUT_PERMISSION,
-                hasShortcutsPermission(mApp.getContext()));
+                hasShortcutsPermission(mContext));
         mBgAllAppsList.setFlags(FLAG_QUIET_MODE_CHANGE_PERMISSION,
-                mApp.getContext().checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
+                mContext.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
                         == PackageManager.PERMISSION_GRANTED);
 
         mBgAllAppsList.getAndResetChangeFlag();
@@ -827,7 +850,7 @@
                         workspaceIconRequest.get().iconBlob,
                         false /* useLowResIcon= */
                 );
-                if (!iconRequestInfo.loadIconFromDbBlob(mApp.getContext())) {
+                if (!iconRequestInfo.loadIconFromDbBlob(mContext)) {
                     Log.d(TAG, "AppInfo Icon failed to load from blob, using cache.");
                     mIconCache.getTitleAndIcon(
                             appInfo,
@@ -853,7 +876,7 @@
         if (mBgAllAppsList.hasShortcutHostPermission()) {
             for (UserHandle user : mUserCache.getUserProfiles()) {
                 if (mUserManager.isUserUnlocked(user)) {
-                    List<ShortcutInfo> shortcuts = new ShortcutRequest(mApp.getContext(), user)
+                    List<ShortcutInfo> shortcuts = new ShortcutRequest(mContext, user)
                             .query(ShortcutRequest.ALL);
                     allShortcuts.addAll(shortcuts);
                     mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
@@ -864,7 +887,7 @@
     }
 
     private void loadFolderNames() {
-        FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
+        FolderNameProvider provider = FolderNameProvider.newInstance(mContext,
                 mBgAllAppsList.data, FolderNameProvider.getCollectionForSuggestions(mBgDataModel));
 
         synchronized (mBgDataModel) {
@@ -874,7 +897,7 @@
                     .forEach(info -> {
                         FolderInfo fi = (FolderInfo) info;
                         FolderNameInfos suggestionInfos = new FolderNameInfos();
-                        provider.getSuggestedFolderName(mApp.getContext(), fi.getAppContents(),
+                        provider.getSuggestedFolderName(mContext, fi.getAppContents(),
                                 suggestionInfos);
                         fi.suggestedFolderNames = suggestionInfos;
                     });
@@ -891,4 +914,10 @@
             Log.d(TAG, label);
         }
     }
+
+    @AssistedFactory
+    public interface LoaderTaskFactory {
+
+        LoaderTask newLoaderTask(BaseLauncherBinder binder, UserManagerState userState);
+    }
 }
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index feae632..64b9c1c 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -73,6 +73,8 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils;
@@ -91,10 +93,13 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import javax.inject.Inject;
+
 /**
  * Utility class which maintains an instance of Launcher database and provides utility methods
  * around it.
  */
+@LauncherAppSingleton
 public class ModelDbController {
     private static final String TAG = "ModelDbController";
 
@@ -105,17 +110,25 @@
     protected DatabaseHelper mOpenHelper;
 
     private final Context mContext;
+    private final InvariantDeviceProfile mIdp;
+    private final LauncherPrefs mPrefs;
+    private final UserCache mUserCache;
 
-    public ModelDbController(Context context) {
+    @Inject
+    ModelDbController(
+            @ApplicationContext Context context,
+            InvariantDeviceProfile idp,
+            LauncherPrefs prefs,
+            UserCache userCache) {
         mContext = context;
+        mIdp = idp;
+        mPrefs = prefs;
+        mUserCache = userCache;
     }
 
     private void printDBs(String prefix) {
         try {
-            File directory = new File(
-                    mContext.getDatabasePath(InvariantDeviceProfile.INSTANCE.get(mContext).dbFile)
-                            .getParent()
-            );
+            File directory = new File(mContext.getDatabasePath(mIdp.dbFile).getParent());
             if (directory.exists()) {
                 for (File file : directory.listFiles()) {
                     Log.d("b/353505773", prefix + "Database file: " + file.getName());
@@ -130,9 +143,9 @@
 
     private synchronized void createDbIfNotExists() {
         if (mOpenHelper == null) {
-            String dbFile = LauncherPrefs.get(mContext).get(DB_FILE);
+            String dbFile = mPrefs.get(DB_FILE);
             if (dbFile.isEmpty()) {
-                dbFile = InvariantDeviceProfile.INSTANCE.get(mContext).dbFile;
+                dbFile = mIdp.dbFile;
             }
             mOpenHelper = createDatabaseHelper(false /* forMigration */, dbFile);
             printDBs("before: ");
@@ -144,7 +157,7 @@
     protected DatabaseHelper createDatabaseHelper(boolean forMigration, String dbFile) {
         // Set the flag for empty DB
         Runnable onEmptyDbCreateCallback = forMigration ? () -> { }
-                : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbFile).to(true));
+                : () -> mPrefs.putSync(getEmptyDbCreatedKey(dbFile).to(true));
 
         DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbFile,
                 this::getSerialNumberForUser, onEmptyDbCreateCallback);
@@ -169,12 +182,12 @@
      * Refer {@link SQLiteDatabase#query}
      */
     @WorkerThread
-    public Cursor query(String table, String[] projection, String selection,
+    public Cursor query(String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
         createDbIfNotExists();
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Cursor result = db.query(
-                table, projection, selection, selectionArgs, null, null, sortOrder);
+                TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
 
         final Bundle extra = new Bundle();
         extra.putString(EXTRA_DB_NAME, mOpenHelper.getDatabaseName());
@@ -186,12 +199,12 @@
      * Refer {@link SQLiteDatabase#insert(String, String, ContentValues)}
      */
     @WorkerThread
-    public int insert(String table, ContentValues initialValues) {
+    public int insert(ContentValues initialValues) {
         createDbIfNotExists();
 
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         addModifiedTime(initialValues);
-        int rowId = mOpenHelper.dbInsertAndCheck(db, table, initialValues);
+        int rowId = mOpenHelper.dbInsertAndCheck(db, TABLE_NAME, initialValues);
         if (rowId >= 0) {
             onAddOrDeleteOp(db);
         }
@@ -202,11 +215,11 @@
      * Refer {@link SQLiteDatabase#delete(String, String, String[])}
      */
     @WorkerThread
-    public int delete(String table, String selection, String[] selectionArgs) {
+    public int delete(String selection, String[] selectionArgs) {
         createDbIfNotExists();
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 
-        int count = db.delete(table, selection, selectionArgs);
+        int count = db.delete(TABLE_NAME, selection, selectionArgs);
         if (count > 0) {
             onAddOrDeleteOp(db);
         }
@@ -217,14 +230,12 @@
      * Refer {@link SQLiteDatabase#update(String, ContentValues, String, String[])}
      */
     @WorkerThread
-    public int update(String table, ContentValues values,
-            String selection, String[] selectionArgs) {
+    public int update(ContentValues values, String selection, String[] selectionArgs) {
         createDbIfNotExists();
 
         addModifiedTime(values);
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        int count = db.update(table, values, selection, selectionArgs);
-        return count;
+        return db.update(TABLE_NAME, values, selection, selectionArgs);
     }
 
     /**
@@ -261,7 +272,7 @@
     public void createEmptyDB() {
         createDbIfNotExists();
         mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
-        LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey().to(true));
+        mPrefs.putSync(getEmptyDbCreatedKey().to(true));
     }
 
     /**
@@ -292,7 +303,6 @@
                 mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
     }
 
-
     /**
      * Resets the launcher DB if we should reset it.
      */
@@ -302,11 +312,10 @@
         }
         FileLog.d(TAG, "resetLauncherDb: Migration failed: resetting launcher database");
         createEmptyDB();
-        LauncherPrefs.get(mContext).putSync(
-                getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
+        mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
 
         // Write the grid state to avoid another migration
-        new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+        new DeviceGridState(mIdp).writeToPrefs(mContext);
     }
 
     /**
@@ -326,7 +335,7 @@
     }
 
     private boolean isThereExistingDb() {
-        if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+        if (mPrefs.get(getEmptyDbCreatedKey())) {
             // If we already have a new DB, ignore migration
             FileLog.d(TAG, "isThereExistingDb: new DB already created, skipping migration");
             return true;
@@ -335,8 +344,7 @@
     }
 
     private boolean isGridMigrationNecessary() {
-        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
-        if (GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+        if (GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) {
             return true;
         }
         FileLog.d(TAG, "isGridMigrationNecessary: no grid migration needed");
@@ -344,8 +352,7 @@
     }
 
     private boolean isCurrentDbSameAsTarget() {
-        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
-        String targetDbName = new DeviceGridState(idp).getDbFile();
+        String targetDbName = new DeviceGridState(mIdp).getDbFile();
         if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
             FileLog.e(TAG, "isCurrentDbSameAsTarget: target db is same as current"
                     + " current db: " + mOpenHelper.getDatabaseName()
@@ -367,7 +374,6 @@
             return;
         }
 
-        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
         DatabaseHelper oldHelper = mOpenHelper;
 
         // We save the existing db's before creating the destination db helper so we know what logic
@@ -376,12 +382,12 @@
                 .filter(dbName -> mContext.getDatabasePath(dbName).exists())
                 .collect(Collectors.toList());
 
-        mOpenHelper = createDatabaseHelper(true, new DeviceGridState(idp).getDbFile());
+        mOpenHelper = createDatabaseHelper(true, new DeviceGridState(mIdp).getDbFile());
         try {
             // This is the current grid we have, given by the mContext
             DeviceGridState srcDeviceState = new DeviceGridState(mContext);
             // This is the state we want to migrate to that is given by the idp
-            DeviceGridState destDeviceState = new DeviceGridState(idp);
+            DeviceGridState destDeviceState = new DeviceGridState(mIdp);
 
             boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
             GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic();
@@ -404,10 +410,10 @@
             ModelDelegate modelDelegate) {
         if (!migrateGridIfNeeded(modelDelegate)) {
             if (restoreEventLogger != null) {
-                if (LauncherPrefs.get(mContext).get(NO_DB_FILES_RESTORED)) {
+                if (mPrefs.get(NO_DB_FILES_RESTORED)) {
                     restoreEventLogger.logLauncherItemsRestoreFailed(DATA_TYPE_DB_FILE, 1,
                             RestoreError.DATABASE_FILE_NOT_RESTORED);
-                    LauncherPrefs.get(mContext).put(NO_DB_FILES_RESTORED, false);
+                    mPrefs.put(NO_DB_FILES_RESTORED, false);
                     FileLog.d(TAG, "There is no data to migrate: resetting launcher database");
                 } else {
                     restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
@@ -416,11 +422,10 @@
             }
             FileLog.d(TAG, "tryMigrateDB: Migration failed: resetting launcher database");
             createEmptyDB();
-            LauncherPrefs.get(mContext).putSync(
-                    getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
+            mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
 
             // Write the grid state to avoid another migration
-            new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+            new DeviceGridState(mIdp).writeToPrefs(mContext);
         } else if (restoreEventLogger != null) {
             restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
         }
@@ -434,17 +439,16 @@
      */
     private boolean migrateGridIfNeeded(ModelDelegate modelDelegate) {
         createDbIfNotExists();
-        if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+        if (mPrefs.get(getEmptyDbCreatedKey())) {
             // If we have already create a new DB, ignore migration
             FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
             return false;
         }
-        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
-        if (!GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+        if (!GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) {
             FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed");
             return true;
         }
-        String targetDbName = new DeviceGridState(idp).getDbFile();
+        String targetDbName = new DeviceGridState(mIdp).getDbFile();
         if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
             FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current"
                     + " current db: " + mOpenHelper.getDatabaseName()
@@ -462,7 +466,7 @@
             // This is the current grid we have, given by the mContext
             DeviceGridState srcDeviceState = new DeviceGridState(mContext);
             // This is the state we want to migrate to that is given by the idp
-            DeviceGridState destDeviceState = new DeviceGridState(idp);
+            DeviceGridState destDeviceState = new DeviceGridState(mIdp);
             boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
             return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState,
                     destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb,
@@ -611,7 +615,7 @@
     }
 
     private void clearFlagEmptyDbCreated() {
-        LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey());
+        mPrefs.removeSync(getEmptyDbCreatedKey());
     }
 
     /**
@@ -625,7 +629,7 @@
     public synchronized void loadDefaultFavoritesIfNecessary() {
         createDbIfNotExists();
 
-        if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+        if (mPrefs.get(getEmptyDbCreatedKey())) {
             Log.d(TAG, "loading default workspace");
 
             LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
@@ -737,10 +741,9 @@
     }
 
     private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) {
-        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
-        int defaultLayout = idp.demoModeLayoutId != 0
+        int defaultLayout = mIdp.demoModeLayoutId != 0
                 && mContext.getSystemService(UserManager.class).isDemoUser()
-                ? idp.demoModeLayoutId : idp.defaultLayoutId;
+                ? mIdp.demoModeLayoutId : mIdp.defaultLayoutId;
 
         return new DefaultLayoutParser(mContext, widgetHolder,
                 mOpenHelper, mContext.getResources(), defaultLayout);
@@ -766,6 +769,6 @@
      * Returns the serial number for the provided user
      */
     public long getSerialNumberForUser(UserHandle user) {
-        return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user);
+        return mUserCache.getSerialNumberForUser(user);
     }
 }
diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
index 7ba2dad..8b6c369 100644
--- a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
+++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
@@ -114,7 +114,7 @@
     override fun onUpdateSessionDisplay(key: PackageUserKey, info: SessionInfo) {
         /** Updates the icons and label of all pending icons for the provided package name. */
         taskExecutor.accept { controller, _, _ ->
-            controller.app.iconCache.updateSessionCache(key, info)
+            controller.iconCache.updateSessionCache(key, info)
         }
         taskExecutor.accept(
             CacheDataUpdatedTask(
@@ -128,7 +128,7 @@
     override fun onInstallSessionCreated(sessionInfo: PackageInstallInfo) {
         if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
             taskExecutor.accept { taskController, _, apps ->
-                apps.addPromiseApp(taskController.app.context, sessionInfo)
+                apps.addPromiseApp(taskController.context, sessionInfo)
                 taskController.bindApplicationsIfNeeded()
             }
         }
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
index 5566482..f17ca32 100644
--- a/src/com/android/launcher3/model/ModelTaskController.kt
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -16,27 +16,34 @@
 
 package com.android.launcher3.model
 
-import com.android.launcher3.LauncherAppState
+import android.content.Context
 import com.android.launcher3.LauncherModel
 import com.android.launcher3.LauncherModel.CallbackTask
 import com.android.launcher3.celllayout.CellPosMapper
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.BgDataModel.FixedContainerItems
 import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.util.PackageUserKey
 import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder
 import java.util.Objects
-import java.util.concurrent.Executor
 import java.util.function.Predicate
+import javax.inject.Inject
 
 /** Class with utility methods and properties for running a LauncherModel Task */
-class ModelTaskController(
-    val app: LauncherAppState,
+class ModelTaskController
+@Inject
+constructor(
+    @ApplicationContext val context: Context,
+    val iconCache: IconCache,
     val dataModel: BgDataModel,
     val allAppsList: AllAppsList,
-    private val model: LauncherModel,
-    private val uiExecutor: Executor,
+    val model: LauncherModel,
 ) {
 
+    private val uiExecutor = MAIN_EXECUTOR
+
     /** Schedules a {@param task} to be executed on the current callbacks. */
     fun scheduleCallbackTask(task: CallbackTask) {
         for (cb in model.callbacks) {
@@ -78,7 +85,7 @@
 
     fun bindUpdatedWidgets(dataModel: BgDataModel) {
         val allWidgets =
-            WidgetsListBaseEntriesBuilder(app.context)
+            WidgetsListBaseEntriesBuilder(context)
                 .build(dataModel.widgetsModel.widgetsByPackageItemForPicker)
         scheduleCallbackTask { it.bindAllWidgets(allWidgets) }
     }
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 0332775..2650e03 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.model;
 
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
@@ -229,7 +228,7 @@
         }).executeOnModelThread();
     }
 
-    private void notifyItemModified(ItemInfo item) {
+    public void notifyItemModified(ItemInfo item) {
         notifyOtherCallbacks(c -> c.bindItemsModified(Collections.singletonList(item)));
     }
 
@@ -253,7 +252,7 @@
             item.onAddToDatabase(writer);
             writer.put(Favorites._ID, item.id);
 
-            mModel.getModelDbController().insert(Favorites.TABLE_NAME, writer.getValues(mContext));
+            mModel.getModelDbController().insert(writer.getValues(mContext));
             synchronized (mBgDataModel) {
                 checkItemInfoLocked(item.id, item, stackTrace);
                 mBgDataModel.addItem(mContext, item, true);
@@ -292,7 +291,7 @@
         notifyDelete(items);
         enqueueDeleteRunnable(newModelTask(() -> {
             for (ItemInfo item : items) {
-                mModel.getModelDbController().delete(TABLE_NAME, itemIdMatch(item.id), null);
+                mModel.getModelDbController().delete(itemIdMatch(item.id), null);
                 mBgDataModel.removeItem(mContext, item);
                 verifier.verifyModel();
             }
@@ -307,12 +306,12 @@
         notifyDelete(Collections.singleton(info));
 
         enqueueDeleteRunnable(newModelTask(() -> {
-            mModel.getModelDbController().delete(Favorites.TABLE_NAME,
+            mModel.getModelDbController().delete(
                     Favorites.CONTAINER + "=" + info.id, null);
             mBgDataModel.removeItem(mContext, info.getContents());
             info.getContents().clear();
 
-            mModel.getModelDbController().delete(Favorites.TABLE_NAME,
+            mModel.getModelDbController().delete(
                     Favorites._ID + "=" + info.id, null);
             mBgDataModel.removeItem(mContext, info);
             verifier.verifyModel();
@@ -411,7 +410,7 @@
         @Override
         public void runImpl() {
             mModel.getModelDbController().update(
-                    TABLE_NAME, mWriter.get().getValues(mContext), itemIdMatch(mItemId), null);
+                    mWriter.get().getValues(mContext), itemIdMatch(mItemId), null);
             updateItemArrays(mItem, mItemId);
         }
     }
@@ -433,7 +432,7 @@
                     ItemInfo item = mItems.get(i);
                     final int itemId = item.id;
                     mModel.getModelDbController().update(
-                            TABLE_NAME, mValues.get(i), itemIdMatch(itemId), null);
+                            mValues.get(i), itemIdMatch(itemId), null);
                     updateItemArrays(item, itemId);
                 }
                 t.commit();
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index a216042..a3561ed 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -52,11 +52,11 @@
             try {
                 // For instant apps we do not get package-add. Use setting events to update
                 // any pinned icons.
-                Context context = taskController.getApp().getContext();
+                Context context = taskController.getContext();
                 ApplicationInfo ai = context
                         .getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
                 if (InstantAppResolver.newInstance(context).isInstantApp(ai)) {
-                    taskController.getApp().getModel().newModelCallbacks()
+                    taskController.getModel().newModelCallbacks()
                             .onPackageAdded(ai.packageName, mInstallInfo.user);
                 }
             } catch (PackageManager.NameNotFoundException e) {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 3cdb250..04f3faa 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -38,7 +38,6 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.Flags;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.config.FeatureFlags;
@@ -106,9 +105,8 @@
     @Override
     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();
+        final Context context = taskController.getContext();
+        final IconCache iconCache = taskController.getIconCache();
 
         final String[] packages = mPackages;
         final int packageCount = packages.length;
@@ -433,7 +431,7 @@
             // Load widgets for the new package. Changes due to app updates are handled through
             // AppWidgetHost events, this is just to initialize the long-press options.
             for (int i = 0; i < packageCount; i++) {
-                dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
+                dataModel.widgetsModel.update(new PackageUserKey(packages[i], mUser));
             }
             taskController.bindUpdatedWidgets(dataModel);
         }
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 9e3f0e1..9ae8092 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -22,7 +22,6 @@
 import android.content.pm.LauncherApps;
 import android.os.UserHandle;
 
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.util.ApplicationInfoWrapper;
 import com.android.launcher3.util.PackageUserKey;
@@ -43,9 +42,10 @@
     private final Context mContext;
     private final Set<PackageUserKey> mPackages;
 
-    public SdCardAvailableReceiver(LauncherAppState app, Set<PackageUserKey> packages) {
-        mModel = app.getModel();
-        mContext = app.getContext();
+    public SdCardAvailableReceiver(
+            Context context, LauncherModel model, Set<PackageUserKey> packages) {
+        mContext = context;
+        mModel = model;
         mPackages = packages;
     }
 
diff --git a/src/com/android/launcher3/model/SessionFailureTask.kt b/src/com/android/launcher3/model/SessionFailureTask.kt
index 8baf568..6ed5178 100644
--- a/src/com/android/launcher3/model/SessionFailureTask.kt
+++ b/src/com/android/launcher3/model/SessionFailureTask.kt
@@ -33,9 +33,9 @@
         dataModel: BgDataModel,
         apps: AllAppsList,
     ) {
-        val iconCache = taskController.app.iconCache
+        val iconCache = taskController.iconCache
         val isAppArchived =
-            ApplicationInfoWrapper(taskController.app.context, packageName, user).isArchived()
+            ApplicationInfoWrapper(taskController.context, packageName, user).isArchived()
         synchronized(dataModel) {
             if (isAppArchived) {
                 val updatedItems = mutableListOf<WorkspaceItemInfo>()
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.kt b/src/com/android/launcher3/model/ShortcutsChangedTask.kt
index 56e9e43..d6759e2 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.kt
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.kt
@@ -40,8 +40,7 @@
         dataModel: BgDataModel,
         apps: AllAppsList,
     ) {
-        val app = taskController.app
-        val context = app.context
+        val context = taskController.context
         // Find WorkspaceItemInfo's that have changed on the workspace.
         val matchingWorkspaceItems = ArrayList<WorkspaceItemInfo>()
 
@@ -88,7 +87,7 @@
                     .filter { itemInfo: WorkspaceItemInfo -> shortcutId == itemInfo.deepShortcutId }
                     .forEach { workspaceItemInfo: WorkspaceItemInfo ->
                         workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context)
-                        app.iconCache.getShortcutIcon(
+                        taskController.iconCache.getShortcutIcon(
                             workspaceItemInfo,
                             CacheableShortcutInfo(fullDetails, infoWrapper),
                         )
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 3dc5ff3..4d28ccb 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -23,7 +23,6 @@
 
 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;
@@ -55,8 +54,7 @@
     @Override
     public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
             @NonNull AllAppsList apps) {
-        LauncherAppState app = taskController.getApp();
-        Context context = app.getContext();
+        Context context = taskController.getContext();
 
         HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
         if (mIsUserUnlocked) {
@@ -92,7 +90,7 @@
                         }
                         si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
                         si.updateFromDeepShortcutInfo(shortcut, context);
-                        app.getIconCache().getShortcutIcon(si, shortcut);
+                        taskController.getIconCache().getShortcutIcon(si, shortcut);
                     } else {
                         si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
                     }
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 52b142d..f2144c0 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -27,6 +27,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.ApplicationContext;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.cache.CachedObject;
 import com.android.launcher3.model.data.PackageItemInfo;
@@ -54,6 +55,8 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import javax.inject.Inject;
+
 /**
  * Widgets data model that is used by the adapters of the widget views and controllers.
  *
@@ -68,6 +71,29 @@
     private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsByPackageItem = new HashMap<>();
     @Nullable private WidgetValidityCheckForPicker mWidgetValidityCheckForPicker = null;
 
+    private final Context mContext;
+    private final InvariantDeviceProfile mIdp;
+    private final IconCache mIconCache;
+    private final AppFilter mAppFilter;
+
+    @Inject
+    public WidgetsModel(
+            @ApplicationContext Context context,
+            InvariantDeviceProfile idp,
+            IconCache iconCache,
+            AppFilter appFilter) {
+        mContext = context;
+        mIdp = idp;
+        mIconCache = iconCache;
+        mAppFilter = appFilter;
+    }
+
+    public WidgetsModel(Context context) {
+        this(context,
+                LauncherAppState.getIDP(context),
+                LauncherAppState.getInstance(context).getIconCache(), new AppFilter(context));
+    }
+
     /**
      * Returns all widgets keyed by their component key.
      */
@@ -128,36 +154,33 @@
      * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
      *                    only widgets and shortcuts associated with the package/user are.
      */
-    public List<CachedObject> update(
-            LauncherAppState app, @Nullable PackageUserKey packageUser) {
+    public List<CachedObject> update(@Nullable PackageUserKey packageUser) {
         if (!WIDGETS_ENABLED) {
             return new ArrayList<>();
         }
         Preconditions.assertWorkerThread();
 
-        Context context = app.getContext();
         final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
         List<CachedObject> updatedItems = new ArrayList<>();
         try {
-            InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
             // Widgets
-            WidgetManagerHelper widgetManager = new WidgetManagerHelper(context);
+            WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
             for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
                 LauncherAppWidgetProviderInfo launcherWidgetInfo =
-                        LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
+                        LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo);
 
                 widgetsAndShortcuts.add(new WidgetItem(
-                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
+                        launcherWidgetInfo, mIdp, mIconCache, mContext));
                 updatedItems.add(launcherWidgetInfo);
             }
 
             // Shortcuts
             for (ShortcutConfigActivityInfo info :
-                    queryList(context, packageUser)) {
-                widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache()));
+                    queryList(mContext, packageUser)) {
+                widgetsAndShortcuts.add(new WidgetItem(info, mIconCache));
                 updatedItems.add(info);
             }
-            setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
+            setWidgetsAndShortcuts(widgetsAndShortcuts, packageUser);
         } catch (Exception e) {
             if (!FeatureFlags.IS_STUDIO_BUILD && Utilities.isBinderSizeError(e)) {
                 // the returned value may be incomplete and will not be refreshed until the next
@@ -172,14 +195,14 @@
         return updatedItems;
     }
 
-    private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
-            LauncherAppState app, @Nullable PackageUserKey packageUser) {
+    private synchronized void setWidgetsAndShortcuts(
+            ArrayList<WidgetItem> rawWidgetsShortcuts, @Nullable PackageUserKey packageUser) {
         if (DEBUG) {
             Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
         }
 
         // Refresh the validity checker with latest app state.
-        mWidgetValidityCheckForPicker = new WidgetValidityCheckForPicker(app);
+        mWidgetValidityCheckForPicker = new WidgetValidityCheckForPicker(mIdp, mAppFilter);
 
         // Temporary cache for {@link PackageItemInfos} to avoid having to go through
         // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
@@ -196,19 +219,17 @@
         // add and update.
         mWidgetsByPackageItem.putAll(rawWidgetsShortcuts.stream()
                 .filter(new WidgetFlagCheck())
-                .flatMap(widgetItem -> getPackageUserKeys(app.getContext(), widgetItem).stream()
+                .flatMap(widgetItem -> getPackageUserKeys(mContext, widgetItem).stream()
                         .map(key -> new Pair<>(packageItemInfoCache.getOrCreate(key), widgetItem)))
                 .collect(groupingBy(pair -> pair.first, mapping(pair -> pair.second, toList()))));
 
         // Update each package entry
-        IconCache iconCache = app.getIconCache();
         for (PackageItemInfo p : packageItemInfoCache.values()) {
-            iconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes());
+            mIconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes());
         }
     }
 
-    public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
-            LauncherAppState app) {
+    public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user) {
         if (!WIDGETS_ENABLED) {
             return;
         }
@@ -220,11 +241,10 @@
                     WidgetItem item = items.get(i);
                     if (item.user.equals(user)) {
                         if (item.activityInfo != null) {
-                            items.set(i, new WidgetItem(item.activityInfo, app.getIconCache()));
+                            items.set(i, new WidgetItem(item.activityInfo, mIconCache));
                         } else {
-                            items.set(i, new WidgetItem(item.widgetInfo,
-                                    app.getInvariantDeviceProfile(), app.getIconCache(),
-                                    app.getContext()));
+                            items.set(i, new WidgetItem(
+                                    item.widgetInfo, mIdp, mIconCache, mContext));
                         }
                     }
                 }
@@ -277,9 +297,9 @@
         private final InvariantDeviceProfile mIdp;
         private final AppFilter mAppFilter;
 
-        WidgetValidityCheckForPicker(LauncherAppState app) {
-            mIdp = app.getInvariantDeviceProfile();
-            mAppFilter = new AppFilter(app.getContext());
+        WidgetValidityCheckForPicker(InvariantDeviceProfile idp, AppFilter appFilter) {
+            mIdp = idp;
+            mAppFilter = appFilter;
         }
 
         @Override
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 99f2837..7b8f218 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -18,6 +18,7 @@
 import android.annotation.SuppressLint
 import android.appwidget.AppWidgetProviderInfo
 import android.content.ComponentName
+import android.content.Context
 import android.content.Intent
 import android.content.pm.LauncherApps
 import android.content.pm.LauncherApps.ShortcutQuery
@@ -29,10 +30,10 @@
 import android.util.LongSparseArray
 import com.android.launcher3.Flags
 import com.android.launcher3.InvariantDeviceProfile
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
 import com.android.launcher3.icons.CacheableShortcutInfo
+import com.android.launcher3.icons.IconCache
 import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
 import com.android.launcher3.logging.FileLog
 import com.android.launcher3.model.data.AppInfo
@@ -70,7 +71,10 @@
     private val launcherApps: LauncherApps,
     private val pendingPackages: MutableSet<PackageUserKey>,
     private val shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo>,
-    private val app: LauncherAppState,
+    private val context: Context,
+    private val idp: InvariantDeviceProfile,
+    private val iconCache: IconCache,
+    private val isSafeMode: Boolean,
     private val bgDataModel: BgDataModel,
     private val widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?>,
     private val installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>,
@@ -82,9 +86,7 @@
     private val allDeepShortcuts: MutableList<CacheableShortcutInfo>,
 ) {
 
-    private val isSafeMode = app.isSafeModeEnabled
     private val tempPackageKey = PackageUserKey(null, null)
-    private val iconCache = app.iconCache
 
     /**
      * This is the entry point for processing 1 workspace item. This method is like the midfielder
@@ -159,7 +161,7 @@
             )
             return
         }
-        val appInfoWrapper = ApplicationInfoWrapper(app.context, targetPkg, c.user)
+        val appInfoWrapper = ApplicationInfoWrapper(context, targetPkg, c.user)
         var validTarget = launcherApps.isPackageEnabled(targetPkg, c.user)
 
         // If it's a deep shortcut, we'll use pinned shortcuts to restore it
@@ -306,7 +308,7 @@
                         )
                         return
                     }
-                    info = WorkspaceItemInfo(pinnedShortcut, app.context)
+                    info = WorkspaceItemInfo(pinnedShortcut, context)
                     // If the pinned deep shortcut is no longer published,
                     // use the last saved icon instead of the default.
                     val csi = CacheableShortcutInfo(pinnedShortcut, appInfoWrapper)
@@ -369,7 +371,7 @@
                     info,
                     activityInfo,
                     userCache.getUserInfo(c.user),
-                    ApiWrapper.INSTANCE[app.context],
+                    ApiWrapper.INSTANCE[context],
                     pmHelper,
                 )
             }
@@ -529,7 +531,7 @@
                         (si == null) &&
                         (lapi == null) &&
                         !(Flags.enableSupportForArchiving() &&
-                            ApplicationInfoWrapper(app.context, component.packageName, c.user)
+                            ApplicationInfoWrapper(context, component.packageName, c.user)
                                 .isArchived())
                 ) {
                     // Restore never started
@@ -553,7 +555,7 @@
                     if (si == null) 0 else (si.getProgress() * 100).toInt()
                 appWidgetInfo.pendingItemInfo =
                     WidgetsModel.newPendingItemInfo(
-                        app.context,
+                        context,
                         appWidgetInfo.providerName,
                         appWidgetInfo.user,
                     )
@@ -563,7 +565,7 @@
                 WidgetSizes.updateWidgetSizeRangesAsync(
                     appWidgetInfo.appWidgetId,
                     lapi,
-                    app.context,
+                    context,
                     appWidgetInfo.spanX,
                     appWidgetInfo.spanY,
                 )
@@ -586,7 +588,7 @@
                         " appWidgetId: ${c.appWidgetId}," +
                         " component=${component}",
                 )
-                logWidgetInfo(app.invariantDeviceProfile, lapi)
+                logWidgetInfo(idp, lapi)
             }
         }
         c.checkAndAddItem(appWidgetInfo, bgDataModel, memoryLogger)
diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
index 1a6d178..17f1615 100644
--- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
+++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
@@ -21,7 +21,7 @@
 import android.util.LongSparseArray;
 
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.ItemInfo;
@@ -31,23 +31,37 @@
 
 import java.util.ArrayList;
 
+import javax.inject.Inject;
+
 /**
  * Utility class to help find space for new workspace items
  */
 public class WorkspaceItemSpaceFinder {
 
+    private BgDataModel mDataModel;
+    private InvariantDeviceProfile mIDP;
+    private LauncherModel mModel;
+
+    @Inject
+    WorkspaceItemSpaceFinder(
+            BgDataModel dataModel, InvariantDeviceProfile idp, LauncherModel model) {
+        mDataModel = dataModel;
+        mIDP = idp;
+        mModel = model;
+    }
+
     /**
      * Find a position on the screen for the given size or adds a new screen.
      *
      * @return screenId and the coordinates for the item in an int array of size 3.
      */
-    public int[] findSpaceForItem(LauncherAppState app, BgDataModel dataModel,
+    public int[] findSpaceForItem(
             IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
         LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
 
         // Use sBgItemsIdMap as all the items are already loaded.
-        synchronized (dataModel) {
-            for (ItemInfo info : dataModel.itemsIdMap) {
+        synchronized (mDataModel) {
+            for (ItemInfo info : mDataModel.itemsIdMap) {
                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
                     ArrayList<ItemInfo> items = screenItems.get(info.screenId);
                     if (items == null) {
@@ -75,7 +89,7 @@
         for (int screen = 0; screen < screenCount; screen++) {
             screenId = workspaceScreens.get(screen);
             if (!screensToExclude.contains(screenId) && findNextAvailableIconSpaceInScreen(
-                    app, screenItems.get(screenId), coordinates, spanX, spanY)) {
+                    screenItems.get(screenId), coordinates, spanX, spanY)) {
                 // We found a space for it
                 found = true;
                 break;
@@ -84,7 +98,7 @@
 
         if (!found) {
             // Still no position found. Add a new screen to the end.
-            screenId = app.getModel().getModelDbController().getNewScreenId();
+            screenId = mModel.getModelDbController().getNewScreenId();
 
             // Save the screen id for binding in the workspace
             workspaceScreens.add(screenId);
@@ -92,7 +106,7 @@
 
             // If we still can't find an empty space, then God help us all!!!
             if (!findNextAvailableIconSpaceInScreen(
-                    app, screenItems.get(screenId), coordinates, spanX, spanY)) {
+                    screenItems.get(screenId), coordinates, spanX, spanY)) {
                 throw new RuntimeException("Can't find space to add the item");
             }
         }
@@ -100,11 +114,8 @@
     }
 
     private boolean findNextAvailableIconSpaceInScreen(
-            LauncherAppState app, ArrayList<ItemInfo> occupiedPos,
-            int[] xy, int spanX, int spanY) {
-        InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
-
-        GridOccupancy occupied = new GridOccupancy(profile.numColumns, profile.numRows);
+            ArrayList<ItemInfo> occupiedPos, int[] xy, int spanX, int spanY) {
+        GridOccupancy occupied = new GridOccupancy(mIDP.numColumns, mIDP.numRows);
         if (occupiedPos != null) {
             for (ItemInfo r : occupiedPos) {
                 occupied.markCells(r, true);
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 9656ac1..4c792a7 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -20,6 +20,9 @@
 
 import static androidx.core.util.Preconditions.checkNotNull;
 
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL;
 import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
 import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
@@ -30,8 +33,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderNameInfos;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logger.LauncherAtom.Attribute;
@@ -42,8 +43,6 @@
 import com.android.launcher3.util.ContentWriter;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 import java.util.OptionalInt;
 import java.util.stream.IntStream;
 
@@ -52,18 +51,6 @@
  */
 public class FolderInfo extends CollectionInfo {
 
-    public static final int NO_FLAGS = 0x00000000;
-
-    /**
-     * The folder is locked in sorted mode
-     */
-    public static final int FLAG_ITEMS_SORTED = 0x00000001;
-
-    /**
-     * It is a work folder
-     */
-    public static final int FLAG_WORK_FOLDER = 0x00000002;
-
     /**
      * The multi-page animation has run for this folder
      */
@@ -95,8 +82,6 @@
         }
     }
 
-    public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest";
-
     public int options;
 
     public FolderNameInfos suggestedFolderNames;
@@ -106,61 +91,16 @@
      */
     private final ArrayList<ItemInfo> contents = new ArrayList<>();
 
-    private ArrayList<FolderListener> mListeners = new ArrayList<>();
-
     public FolderInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
     }
 
-    /** Adds a app or shortcut to the contents ArrayList without animation. */
     @Override
     public void add(@NonNull ItemInfo item) {
-        add(item, false /* animate */);
-    }
-
-    /**
-     * Add an app or shortcut
-     *
-     * @param item
-     */
-    public void add(ItemInfo item, boolean animate) {
-        add(item, getContents().size(), animate);
-    }
-
-    /**
-     * Add an app or shortcut for a specified rank.
-     */
-    public void add(ItemInfo item, int rank, boolean animate) {
-        if (!Folder.willAccept(item)) {
+        if (!willAcceptItemType(item.itemType)) {
             throw new RuntimeException("tried to add an illegal type into a folder");
         }
-
-        rank = Utilities.boundToRange(rank, 0, getContents().size());
-        getContents().add(rank, item);
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAdd(item, rank);
-        }
-        itemsChanged(animate);
-    }
-
-    /**
-     * Remove an app or shortcut. Does not change the DB.
-     *
-     * @param item
-     */
-    public void remove(ItemInfo item, boolean animate) {
-        removeAll(Collections.singletonList(item), animate);
-    }
-
-    /**
-     * Remove all matching app or shortcut. Does not change the DB.
-     */
-    public void removeAll(List<ItemInfo> items, boolean animate) {
-        contents.removeAll(items);
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onRemove(items);
-        }
-        itemsChanged(animate);
+        getContents().add(item);
     }
 
     /**
@@ -197,28 +137,6 @@
         writer.put(LauncherSettings.Favorites.OPTIONS, options);
     }
 
-    public void addListener(FolderListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void removeListener(FolderListener listener) {
-        mListeners.remove(listener);
-    }
-
-    public void itemsChanged(boolean animate) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onItemsChanged(animate);
-        }
-    }
-
-    public interface FolderListener {
-        void onAdd(ItemInfo item, int rank);
-        void onRemove(List<ItemInfo> item);
-        void onItemsChanged(boolean animate);
-        void onTitleChanged(CharSequence title);
-
-    }
-
     public boolean hasOption(int optionFlag) {
         return (options & optionFlag) != 0;
     }
@@ -261,7 +179,6 @@
                 .build();
     }
 
-    @Override
     public void setTitle(@Nullable CharSequence title, ModelWriter modelWriter) {
         // Updating label from null to empty is considered as false touch.
         // Retaining null title(ie., UNLABELED state) allows auto-labeling when new items added.
@@ -289,10 +206,6 @@
         if (modelWriter != null) {
             modelWriter.updateItemInDatabase(this);
         }
-
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onTitleChanged(title);
-        }
     }
 
     /**
@@ -401,4 +314,13 @@
         }
         return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
     }
+
+    /**
+     * Checks if {@code itemType} is a type that can be placed in folders.
+     */
+    public static boolean willAcceptItemType(int itemType) {
+        return itemType == ITEM_TYPE_APPLICATION
+                || itemType == ITEM_TYPE_DEEP_SHORTCUT
+                || itemType == ITEM_TYPE_APP_PAIR;
+    }
 }
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 588e759..ad7696c 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -61,7 +61,6 @@
 import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
 import com.android.launcher3.logger.LauncherAtom.WallpapersContainer;
 import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
-import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ContentWriter;
@@ -536,14 +535,6 @@
     }
 
     /**
-     * Sets the title of the item and writes to DB model if needed.
-     */
-    public void setTitle(@Nullable final CharSequence title,
-            @Nullable final ModelWriter modelWriter) {
-        this.title = title;
-    }
-
-    /**
      * Returns a string ID that is stable for a user session, but may not be persisted
      */
     @Nullable
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 0640bf3..a6f76c4 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.pageindicators;
 
+import java.util.function.Consumer;
+
 /**
  * Base class for a page indicator.
  */
@@ -27,6 +29,14 @@
     void setMarkersCount(int numMarkers);
 
     /**
+     * This is only going to be used by the FolderPagedView's PageIndicator. A refactor is planned
+     * to separate the two purposes of this class, but in the meantime, this indicator will serve to
+     * let the folder snap to the page of its click, and also tell the PageIndicator not to draw
+     * arrows if the click listener is null (at least until after this is refactored).
+     */
+    void setArrowClickListener(Consumer<Direction> listener);
+
+    /**
      * Sets a flag indicating whether to pause scroll.
      * <p>Should be set to {@code true} while the screen is binding or new data is being applied,
      * and to {@code false} once done. This prevents animation conflicts due to scrolling during
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt
new file mode 100644
index 0000000..970d210
--- /dev/null
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 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.pageindicators
+
+interface PageIndicatorArrowClickListener {
+    fun onArrowClick(direction: Direction)
+}
+
+enum class Direction {
+    END,
+    START,
+}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 37f5189..384f876 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -32,11 +32,13 @@
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.VectorDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.IntProperty;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewOutlineProvider;
@@ -51,9 +53,14 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Themes;
 
+import java.util.function.Consumer;
+
 /**
  * {@link PageIndicator} which shows dots per page. The active page is shown with the current
  * accent color.
+ * <p>
+ * TODO(b/402258632): Split PageIndicatorDots into 2 different classes: FolderPageIndicator &
+ * WorkspacePageIndicator. A lot of the functionality in this class is only used by one UI purpose.
  */
 public class PageIndicatorDots extends View implements Insettable, PageIndicator {
 
@@ -68,6 +75,12 @@
     private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
     private static final int ENTER_ANIMATION_DURATION = 400;
 
+    private static final int LARGE_HEIGHT_MULTIPLIER = 12;
+    private static final int SMALL_HEIGHT_MULTIPLIER = 4;
+    private static final int LARGE_WIDTH_MULTIPLIER = 5;
+    private static final int SMALL_WIDTH_MULTIPLIER = 3;
+    private static final float ARROW_TOUCH_BOX_FACTOR = 5f;
+
     private static final int PAGE_INDICATOR_ALPHA = 255;
     private static final int DOT_ALPHA = 128;
     private static final float DOT_ALPHA_FRACTION = 0.5f;
@@ -75,12 +88,14 @@
     private static final int VISIBLE_ALPHA = 255;
     private static final int INVISIBLE_ALPHA = 0;
     private Paint mPaginationPaint;
+    private Consumer<Direction> mOnArrowClickListener;
 
     // This value approximately overshoots to 1.5 times the original size.
     private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
 
     // This is used to optimize the onDraw method by not constructing a new RectF each draw.
     private static final RectF sTempRect = new RectF();
+    private static final RectF sLastActiveRect = new RectF();
 
     private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION =
             new FloatProperty<PageIndicatorDots>("current_position") {
@@ -99,23 +114,27 @@
 
     private static final IntProperty<PageIndicatorDots> PAGINATION_ALPHA =
             new IntProperty<PageIndicatorDots>("pagination_alpha") {
-        @Override
-        public Integer get(PageIndicatorDots obj) {
-            return obj.mPaginationPaint.getAlpha();
-        }
+                @Override
+                public Integer get(PageIndicatorDots obj) {
+                    return obj.mPaginationPaint.getAlpha();
+                }
 
-        @Override
-        public void setValue(PageIndicatorDots obj, int alpha) {
-            obj.mPaginationPaint.setAlpha(alpha);
-            obj.invalidate();
-        }
-    };
+                @Override
+                public void setValue(PageIndicatorDots obj, int alpha) {
+                    obj.mPaginationPaint.setAlpha(alpha);
+                    obj.invalidate();
+                }
+            };
 
     private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper());
     private final float mDotRadius;
     private final float mGapWidth;
     private final float mCircleGap;
     private final boolean mIsRtl;
+    private final VectorDrawable mArrowRight;
+    private final VectorDrawable mArrowLeft;
+    private final Rect mArrowRightBounds = new Rect();
+    private final Rect mArrowLeftBounds = new Rect();
 
     private int mNumPages;
     private int mActivePage;
@@ -167,6 +186,8 @@
                 : DOT_GAP_FACTOR * mDotRadius;
         setOutlineProvider(new MyOutlineProver());
         mIsRtl = Utilities.isRtl(getResources());
+        mArrowRight = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_end);
+        mArrowLeft = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_start);
     }
 
     @Override
@@ -405,6 +426,11 @@
     }
 
     @Override
+    public void setArrowClickListener(Consumer<Direction> listener) {
+        mOnArrowClickListener = listener;
+    }
+
+    @Override
     public void setPauseScroll(boolean pause, boolean isTwoPanels) {
         mIsTwoPanels = isTwoPanels;
 
@@ -419,11 +445,16 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // TODO(b/394355070): Verify Folder Entry Animation works correctly with visual updates
-        // Add extra spacing of mDotRadius on all sides so than entry animation could be run.
+        // Add extra spacing of mDotRadius on all sides so than entry animation could be run
+        // and so the hitboxes of arrows can be clicked easier.
         int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?
-                MeasureSpec.getSize(widthMeasureSpec) : (int) ((mNumPages * 3 + 2) * mDotRadius);
+                MeasureSpec.getSize(widthMeasureSpec)
+                : (int) ((mNumPages * ((enableLauncherVisualRefresh())
+                        ? LARGE_WIDTH_MULTIPLIER : SMALL_WIDTH_MULTIPLIER) + 2) * mDotRadius);
         int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY
-                ? MeasureSpec.getSize(heightMeasureSpec) : (int) (4 * mDotRadius);
+                ? MeasureSpec.getSize(heightMeasureSpec)
+                : (int) (((enableLauncherVisualRefresh())
+                        ? LARGE_HEIGHT_MULTIPLIER : SMALL_HEIGHT_MULTIPLIER) * mDotRadius);
         setMeasuredDimension(width, height);
     }
 
@@ -443,18 +474,51 @@
         float y = getHeight() / 2;
 
         if (mEntryAnimationRadiusFactors != null) {
-            // During entry animation, only draw the circles
-            // TODO(b/394355070): Verify Folder Entry Animation works correctly - visual updates
+            if (enableLauncherVisualRefresh()) {
+                x -= mDotRadius;
+                if (mIsRtl) {
+                    x = getWidth() - x;
+                    circleGap = -circleGap;
+                }
+                sTempRect.top = y - mDotRadius;
+                sTempRect.bottom = y + mDotRadius;
 
-            if (mIsRtl) {
-                x = getWidth() - x;
-                circleGap = -circleGap;
-            }
-            for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
-                mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
-                canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
-                        mPaginationPaint);
-                x += circleGap;
+                for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
+                    if (i == mActivePage) {
+                        if (mIsRtl) {
+                            sTempRect.left = x - (mDotRadius * 3);
+                            sTempRect.right = x + mDotRadius;
+                            x += circleGap - (mDotRadius * 2);
+                        } else {
+                            sTempRect.left = x - mDotRadius;
+                            sTempRect.right = x + (mDotRadius * 3);
+                            x += circleGap + (mDotRadius * 2);
+                        }
+                        scale(sTempRect, mEntryAnimationRadiusFactors[i]);
+                        float scaledRadius = mDotRadius * mEntryAnimationRadiusFactors[i];
+                        mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA);
+                        canvas.drawRoundRect(sTempRect, scaledRadius, scaledRadius,
+                                mPaginationPaint);
+                    } else {
+                        mPaginationPaint.setAlpha(DOT_ALPHA);
+                        canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
+                                mPaginationPaint);
+                        x += circleGap;
+                    }
+                }
+            } else {
+                // During entry animation, only draw the circles
+
+                if (mIsRtl) {
+                    x = getWidth() - x;
+                    circleGap = -circleGap;
+                }
+                for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
+                    mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
+                    canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
+                            mPaginationPaint);
+                    x += circleGap;
+                }
             }
         } else {
             // Save the current alpha value, so we can reset to it again after drawing the dots
@@ -468,12 +532,31 @@
                 sTempRect.bottom = y + mDotRadius;
                 sTempRect.left = x - diameter;
 
-                float posDif = Math.abs(mLastPosition - mCurrentPosition);
+                float currentPosition = mCurrentPosition;
+                float lastPosition = mLastPosition;
+
+                if (mIsRtl) {
+                    currentPosition = mNumPages - currentPosition - 1;
+                    lastPosition = mNumPages - lastPosition - 1;
+                }
+                float posDif = Math.abs(lastPosition - currentPosition);
                 float boundedPosition = (posDif > 1)
-                        ? Math.round(mCurrentPosition)
-                        : mCurrentPosition;
+                        ? Math.round(currentPosition)
+                        : currentPosition;
                 float bounceProgress = (posDif > 1) ? posDif - 1 : 0;
-                float bounceAdjustment = Math.abs(mCurrentPosition - boundedPosition) * diameter;
+                float bounceAdjustment = Math.abs(currentPosition - boundedPosition) * diameter;
+
+                if (mOnArrowClickListener != null && boundedPosition >= 1) {
+                    // Here we draw the Left Arrow
+                    mArrowLeft.setAlpha(alpha);
+                    int size = (int) (mGapWidth * 4);
+                    mArrowLeftBounds.left = (int) (sTempRect.left - mGapWidth - size);
+                    mArrowLeftBounds.top = (int) (y - size / 2);
+                    mArrowLeftBounds.right = (int) (sTempRect.left - mGapWidth);
+                    mArrowLeftBounds.bottom = (int) (y + size / 2);
+                    mArrowLeft.setBounds(mArrowLeftBounds);
+                    mArrowLeft.draw(canvas);
+                }
 
                 // Here we draw the dots, one at a time from the left-most dot to the right-most dot
                 // 1.0 => 000000 000000111111 000000
@@ -495,10 +578,10 @@
                         // While the animation is shifting the active pagination dots size from
                         // the previously active one, to the newly active dot, there is no bounce
                         // adjustment. The bounce happens in the "Overshoot" phase of the animation.
-                        // mLastPosition is used to determine when the currentPosition is just
+                        // lastPosition is used to determine when the currentPosition is just
                         // leaving the page, or if it is in the overshoot phase.
                         if (boundedPosition == i && bounceProgress != 0) {
-                            if (mLastPosition < mCurrentPosition) {
+                            if (lastPosition < currentPosition) {
                                 sTempRect.left -= bounceAdjustment;
                             } else {
                                 sTempRect.right += bounceAdjustment;
@@ -507,19 +590,34 @@
                     } else {
                         sTempRect.right = sTempRect.left + diameter;
 
-                        if (mLastPosition == i && bounceProgress != 0) {
-                            if (mLastPosition > mCurrentPosition) {
+                        if (lastPosition == i && bounceProgress != 0) {
+                            if (lastPosition > currentPosition) {
                                 sTempRect.left += bounceAdjustment;
                             } else {
                                 sTempRect.right -= bounceAdjustment;
                             }
                         }
                     }
+                    if (Math.round(mCurrentPosition) == i) {
+                        sLastActiveRect.set(sTempRect);
+                    }
                     canvas.drawRoundRect(sTempRect, mDotRadius, mDotRadius, mPaginationPaint);
 
                     // TODO(b/394355070) Verify RTL experience works correctly with visual updates
                     sTempRect.left = sTempRect.right + mGapWidth;
                 }
+
+                if (mOnArrowClickListener != null && boundedPosition <= mNumPages - 2) {
+                    // Here we draw the Right Arrow
+                    mArrowRight.setAlpha(alpha);
+                    int size = (int) (mGapWidth * 4);
+                    mArrowRightBounds.left = (int) sTempRect.left;
+                    mArrowRightBounds.top = (int) (y - size / 2);
+                    mArrowRightBounds.right = (int) (int) (sTempRect.left + size);
+                    mArrowRightBounds.bottom = (int) (y + size / 2);
+                    mArrowRight.setBounds(mArrowRightBounds);
+                    mArrowRight.draw(canvas);
+                }
             } else {
                 // Here we draw the dots
                 mPaginationPaint.setAlpha((int) (alpha * DOT_ALPHA_FRACTION));
@@ -538,6 +636,38 @@
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mOnArrowClickListener == null) {
+            // No - Op. Don't care about touch events
+        } else if ((mIsRtl && withinExpandedBounds(mArrowRightBounds, ev))
+                || (!mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev))) {
+            mOnArrowClickListener.accept(Direction.START);
+        } else if ((mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev))
+                || (!mIsRtl && withinExpandedBounds(mArrowRightBounds, ev))) {
+            mOnArrowClickListener.accept(Direction.END);
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    // For larger Touch box
+    private boolean withinExpandedBounds(Rect rect, MotionEvent ev) {
+        RectF scaledRect = new RectF(rect);
+        scale(scaledRect, ARROW_TOUCH_BOX_FACTOR);
+        return scaledRect.contains(ev.getX(), ev.getY());
+    }
+
+    private static void scale(RectF rect, float factor) {
+        float horizontalAdjustment = rect.width() * (factor - 1) / 2;
+        float verticalAdjustment = rect.height() * (factor - 1) / 2;
+
+        rect.top -= verticalAdjustment;
+        rect.bottom += verticalAdjustment;
+
+        rect.left -= horizontalAdjustment;
+        rect.right += horizontalAdjustment;
+    }
+
     private RectF getActiveRect() {
         float startCircle = (int) mCurrentPosition;
         float delta = mCurrentPosition - startCircle;
@@ -590,8 +720,8 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (mEntryAnimationRadiusFactors == null) {
-                // TODO(b/394355070): Verify Outline works correctly with visual updates
-                RectF activeRect = getActiveRect();
+                RectF activeRect = enableLauncherVisualRefresh()
+                        ? sLastActiveRect : getActiveRect();
                 outline.setRoundRect(
                         (int) activeRect.left,
                         (int) activeRect.top,
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index aad1400..39f68bf 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,9 +16,12 @@
 
 package com.android.launcher3.popup;
 
+import static android.multiuser.Flags.enableMovingContentIntoPrivateSpace;
+
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.allapps.AlphabeticalAppsList.PRIVATE_SPACE_PACKAGE;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -65,6 +68,7 @@
 import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -207,7 +211,10 @@
         container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
                 R.layout.popup_container, launcher.getDragLayer(), false);
         container.configureForLauncher(launcher, item);
-        container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts);
+        boolean shouldHideSystemShortcuts = enableMovingContentIntoPrivateSpace()
+                && Objects.equals(item.getTargetPackage(), PRIVATE_SPACE_PACKAGE);
+        container.populateAndShowRows(icon, deepShortcutCount,
+                shouldHideSystemShortcuts ? Collections.emptyList() : systemShortcuts);
         launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
         container.requestFocus();
         return container;
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 5c1a755..9511032 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -26,7 +26,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.dot.DotInfo;
-import com.android.launcher3.dot.FolderDotInfo;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.FolderInfo;
@@ -76,11 +75,7 @@
                 ((BubbleTextView) v).applyDotState(info, true /* animate */);
             } else if (v instanceof FolderIcon icon
                     && info instanceof FolderInfo fi && fi.anyMatch(matcher)) {
-                FolderDotInfo folderDotInfo = new FolderDotInfo();
-                for (ItemInfo si : fi.getContents()) {
-                    folderDotInfo.addDotInfo(getDotInfoForItem(si));
-                }
-                icon.setDotInfo(folderDotInfo);
+                icon.updateDotInfo();
             }
 
             // process all the shortcuts
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.kt b/src/com/android/launcher3/provider/LauncherDbUtils.kt
index c92328d..3641371 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.kt
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.kt
@@ -26,19 +26,17 @@
 import android.os.Process
 import android.os.UserManager
 import android.text.TextUtils
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
 import com.android.launcher3.Utilities
+import com.android.launcher3.dagger.LauncherComponentProvider.appComponent
 import com.android.launcher3.icons.IconCache
-import com.android.launcher3.model.LoaderCursor
 import com.android.launcher3.model.UserManagerState
 import com.android.launcher3.pm.PinRequestHelper
 import com.android.launcher3.pm.UserCache
 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. */
 object LauncherDbUtils {
@@ -155,12 +153,11 @@
                 null,
                 null,
             )
-        val pmHelper = PackageManagerHelper.INSTANCE[context]
         val ums = UserManagerState()
         ums.run {
             init(UserCache.INSTANCE[context], context.getSystemService(UserManager::class.java))
         }
-        val lc = LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper, null)
+        val lc = context.appComponent.loaderCursorFactory.createLoaderCursor(c, ums, null)
         val deletedShortcuts = IntSet()
 
         while (lc.moveToNext()) {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 23941bb..f6ee26b 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -80,6 +80,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 /**
@@ -206,7 +207,8 @@
             LauncherRestoreEventLogger restoreEventLogger =
                     LauncherRestoreEventLogger.Companion.newInstance(context);
             task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger);
-            task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger);
+            task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger,
+                    () -> new AppWidgetHost(context, APPWIDGET_HOST_ID));
             t.commit();
             return true;
         } catch (Exception e) {
@@ -438,14 +440,13 @@
     @WorkerThread
     @VisibleForTesting
     void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller,
-            LauncherRestoreEventLogger restoreEventLogger) {
+            LauncherRestoreEventLogger restoreEventLogger, Supplier<AppWidgetHost> hostSupplier) {
         LauncherPrefs lp = LauncherPrefs.get(context);
         if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
-            AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
             restoreAppWidgetIds(context, controller, restoreEventLogger,
                     IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
                     IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
-                    host);
+                    hostSupplier.get());
         } else {
             FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore");
         }
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 2cc4909..f86fd6a 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -22,6 +22,7 @@
 import static com.android.app.animation.Interpolators.FINAL_FRAME;
 import static com.android.app.animation.Interpolators.INSTANT;
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.clampToProgress;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
@@ -39,6 +40,7 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -53,10 +55,10 @@
     private static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = 0.1f;
     private static final float ALL_APPS_STAGGERED_FADE_THRESHOLD = 0.5f;
 
-    public static final Interpolator ALL_APPS_SCRIM_RESPONDER =
+    private static final Interpolator ALL_APPS_SCRIM_RESPONDER =
             Interpolators.clampToProgress(
                     LINEAR, ALL_APPS_SCRIM_VISIBLE_THRESHOLD, ALL_APPS_STAGGERED_FADE_THRESHOLD);
-    public static final Interpolator ALL_APPS_CLAMPING_RESPONDER =
+    private static final Interpolator ALL_APPS_CLAMPING_RESPONDER =
             Interpolators.clampToProgress(
                     LINEAR,
                     1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
@@ -207,7 +209,16 @@
             }
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
             config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
-            if (launcher.getDeviceProfile().isPhone) {
+            if (Flags.allAppsBlur()) {
+                if (!config.isUserControlled()) {
+                    config.setInterpolator(ANIM_DEPTH, EMPHASIZED_DECELERATE);
+                }
+                config.setInterpolator(ANIM_WORKSPACE_FADE,
+                        clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1));
+                config.setInterpolator(ANIM_HOTSEAT_FADE,
+                        clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1));
+            } else if (launcher.getDeviceProfile().isPhone) {
+                // On phones without blur, reveal the workspace and hotseat when leaving All Apps.
                 config.setInterpolator(ANIM_WORKSPACE_FADE, INSTANT);
                 config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT);
                 config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
@@ -253,7 +264,14 @@
             }
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
             config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
-            if (launcher.getDeviceProfile().isPhone) {
+            if (Flags.allAppsBlur()) {
+                config.setInterpolator(ANIM_DEPTH, LINEAR);
+                config.setInterpolator(ANIM_WORKSPACE_FADE,
+                        clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
+                config.setInterpolator(ANIM_HOTSEAT_FADE,
+                        clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
+            } else if (launcher.getDeviceProfile().isPhone) {
+                // On phones without blur, hide the workspace and hotseat when entering All Apps.
                 config.setInterpolator(ANIM_WORKSPACE_FADE, FINAL_FRAME);
                 config.setInterpolator(ANIM_HOTSEAT_FADE, FINAL_FRAME);
                 config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index d72e6f9..576f176 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -131,7 +131,7 @@
         }
 
         boolean isInAllAppsBottomSheet = mLauncher.isInState(ALL_APPS)
-                && mLauncher.getDeviceProfile().isTablet;
+                && mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet();
 
         final boolean result;
         if (mLongPressState == STATE_COMPLETED) {
diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java
index 9910dc2..c2c1fee 100644
--- a/src/com/android/launcher3/util/ContentWriter.java
+++ b/src/com/android/launcher3/util/ContentWriter.java
@@ -23,7 +23,6 @@
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.model.ModelDbController;
@@ -107,7 +106,7 @@
     public int commit() {
         if (mCommitParams != null) {
             return mCommitParams.mDbController.update(
-                    Favorites.TABLE_NAME, getValues(mContext),
+                    getValues(mContext),
                     mCommitParams.mWhere, mCommitParams.mSelectionArgs);
         }
         return 0;
diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt
index ebf4656..acb3c4e 100644
--- a/src/com/android/launcher3/util/ItemInflater.kt
+++ b/src/com/android/launcher3/util/ItemInflater.kt
@@ -24,6 +24,7 @@
 import android.view.View.OnFocusChangeListener
 import android.view.ViewGroup
 import com.android.launcher3.BubbleTextView
+import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.R
 import com.android.launcher3.apppairs.AppPairIcon
@@ -46,10 +47,11 @@
     private val widgetHolder: LauncherWidgetHolder,
     private val clickListener: OnClickListener,
     private val focusListener: OnFocusChangeListener,
-    private val defaultParent: ViewGroup
+    private val defaultParent: ViewGroup,
 ) where T : Context, T : ActivityContext {
 
-    private val widgetInflater = WidgetInflater(context)
+    private val widgetInflater =
+        WidgetInflater(context, LauncherAppState.getInstance(context).isSafeModeEnabled)
 
     @JvmOverloads
     fun inflateItem(item: ItemInfo, writer: ModelWriter, nullableParent: ViewGroup? = null): View? {
@@ -75,7 +77,7 @@
                     R.layout.folder_icon,
                     context,
                     parent,
-                    item as FolderInfo
+                    item as FolderInfo,
                 )
             Favorites.ITEM_TYPE_APP_PAIR ->
                 return AppPairIcon.inflateIcon(
@@ -83,7 +85,7 @@
                     context,
                     parent,
                     item as AppPairInfo,
-                    BubbleTextView.DISPLAY_WORKSPACE
+                    BubbleTextView.DISPLAY_WORKSPACE,
                 )
             Favorites.ITEM_TYPE_APPWIDGET,
             Favorites.ITEM_TYPE_CUSTOM_APPWIDGET ->
diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
index 7a40abe..53e0bce 100644
--- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
+++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
@@ -123,6 +123,32 @@
         }
     }
 
+    /**
+     * Same as {@link #register(Runnable, int, String...)} above but with additional permission
+     * params utilizine the original {@link Context}.
+     */
+    @AnyThread
+    public void register(@Nullable Runnable completionCallback,
+                         String broadcastPermission, int flags, String... actions) {
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            registerInternal(mContext, completionCallback, broadcastPermission, flags, actions);
+        } else {
+            mHandler.post(() -> registerInternal(mContext, completionCallback, broadcastPermission,
+                    flags, actions));
+        }
+    }
+
+    /** Register broadcast receiver with permission and run completion callback if passed. */
+    @AnyThread
+    private void registerInternal(
+            @NonNull Context context, @Nullable Runnable completionCallback,
+            String broadcastPermission, int flags, String... actions) {
+        context.registerReceiver(this, getFilter(actions), broadcastPermission, null, flags);
+        if (completionCallback != null) {
+            completionCallback.run();
+        }
+    }
+
     /** Same as {@link #register(Runnable, String...)} above but with pkg name. */
     @AnyThread
     public void registerPkgActions(@Nullable String pkg, String... actions) {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 82cc40d..8c01c59 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
 
@@ -219,6 +220,11 @@
                     OptionsPopupView::enterHomeGardening));
         }
         options.add(new OptionItem(launcher,
+                R.string.all_apps_home_screen,
+                R.drawable.ic_apps,
+                LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS,
+                OptionsPopupView::enterAllApps));
+        options.add(new OptionItem(launcher,
                 R.string.settings_button_text,
                 R.drawable.ic_setting,
                 LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
@@ -226,6 +232,20 @@
         return options;
     }
 
+    /**
+     * Used by the options to open All Apps, uses an intent as to not tie the implementation of
+     * opening All Apps with OptionsPopup, instead it uses the public API to open All Apps.
+     */
+    public static boolean enterAllApps(View view) {
+        Launcher launcher = Launcher.getLauncher(view.getContext());
+        launcher.startActivity(
+                new Intent(Intent.ACTION_ALL_APPS)
+                .setComponent(launcher.getComponentName())
+                .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
+        );
+        return true;
+    }
+
     private static boolean enterHomeGardening(View view) {
         Launcher launcher = Launcher.getLauncher(view.getContext());
         launcher.getStateManager().goToState(EDIT_MODE);
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index ce58de1..ec71f31 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -54,8 +54,7 @@
     }
 
     @Override
-    public void setInsets(Rect insets) {
-    }
+    public void setInsets(Rect insets) {}
 
     @Override
     public boolean hasOverlappingRendering() {
diff --git a/src/com/android/launcher3/widget/WidgetInflater.kt b/src/com/android/launcher3/widget/WidgetInflater.kt
index d6cadc7..03f680a 100644
--- a/src/com/android/launcher3/widget/WidgetInflater.kt
+++ b/src/com/android/launcher3/widget/WidgetInflater.kt
@@ -19,14 +19,21 @@
 import android.content.Context
 import com.android.launcher3.BuildConfig
 import com.android.launcher3.Launcher
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
+import com.android.launcher3.dagger.ApplicationContext
 import com.android.launcher3.logging.FileLog
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
 import com.android.launcher3.qsb.QsbContainerView
+import javax.inject.Inject
+import javax.inject.Named
 
 /** Utility class for handling widget inflation taking into account all the restore state updates */
-class WidgetInflater(private val context: Context) {
+class WidgetInflater
+@Inject
+constructor(
+    @ApplicationContext private val context: Context,
+    @Named("SAFE_MODE") private val isSafeModeEnabled: Boolean,
+) {
 
     private val widgetHelper = WidgetManagerHelper(context)
 
@@ -41,9 +48,8 @@
                 )
             }
         }
-        if (LauncherAppState.INSTANCE.get(context).isSafeModeEnabled) {
-            return InflationResult(TYPE_PENDING)
-        }
+        if (isSafeModeEnabled) return InflationResult(TYPE_PENDING)
+
         val appWidgetInfo: LauncherAppWidgetProviderInfo?
         var removalReason = ""
         @RestoreError var logReason = RestoreError.OTHER_WIDGET_INFLATION_FAIL
diff --git a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
index e94f3a0..185c3ee 100644
--- a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
@@ -26,9 +26,12 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.pageindicators.Direction;
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.views.ActivityContext;
 
+import java.util.function.Consumer;
+
 /**
  * Supports two indicator colors, dedicated for personal and work tabs.
  */
@@ -78,6 +81,11 @@
     }
 
     @Override
+    public void setArrowClickListener(Consumer<Direction> listener) {
+        // No-Op. All Apps doesn't need accessibility arrows for single click navigation.
+    }
+
+    @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index a13d63b..6a0d774 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -53,7 +53,7 @@
 	bottomSheetTopPadding: 146.0px (55.61905dp)
 	bottomSheetOpenDuration: 267
 	bottomSheetCloseDuration: 267
-	bottomSheetWorkspaceScale: 1.0
+	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
 	allAppsShiftRange: 2400.0px (914.2857dp)
 	allAppsOpenDuration: 600
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index 3c24885..9e2397c 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -53,7 +53,7 @@
 	bottomSheetTopPadding: 146.0px (55.61905dp)
 	bottomSheetOpenDuration: 267
 	bottomSheetCloseDuration: 267
-	bottomSheetWorkspaceScale: 1.0
+	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
 	allAppsShiftRange: 2400.0px (914.2857dp)
 	allAppsOpenDuration: 600
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index 5e06513..f25ab42 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -53,7 +53,7 @@
 	bottomSheetTopPadding: 114.0px (43.42857dp)
 	bottomSheetOpenDuration: 267
 	bottomSheetCloseDuration: 267
-	bottomSheetWorkspaceScale: 1.0
+	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
 	allAppsShiftRange: 1080.0px (411.42856dp)
 	allAppsOpenDuration: 600
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index d107988..053dd62 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -53,7 +53,7 @@
 	bottomSheetTopPadding: 114.0px (43.42857dp)
 	bottomSheetOpenDuration: 267
 	bottomSheetCloseDuration: 267
-	bottomSheetWorkspaceScale: 1.0
+	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
 	allAppsShiftRange: 1080.0px (411.42856dp)
 	allAppsOpenDuration: 600
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index 47110fa..f772339 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.celllayout;
 
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
@@ -89,7 +88,7 @@
 
                     item.onAddToDatabase(writer);
                     writer.put(LauncherSettings.Favorites._ID, i);
-                    controller.insert(TABLE_NAME, writer.getValues(mContext));
+                    controller.insert(writer.getValues(mContext));
                 }
 
                 for (int i = 0; i < containerItems.size(); i++) {
@@ -97,7 +96,7 @@
                     ItemInfo item = containerItems.get(i);
                     item.onAddToDatabase(writer);
                     writer.put(LauncherSettings.Favorites._ID, count + i);
-                    controller.insert(TABLE_NAME, writer.getValues(mContext));
+                    controller.insert(writer.getValues(mContext));
                 }
                 transaction.commit();
             }
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
index 2e556e8..3405cae 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
@@ -44,7 +44,7 @@
     private fun fillWithWidgets(
         widgetRect: WidgetRect,
         transaction: FavoriteItemsTransaction,
-        screenId: Int
+        screenId: Int,
     ): FavoriteItemsTransaction {
         val initX = widgetRect.cellX
         val initY = widgetRect.cellY
@@ -76,7 +76,7 @@
         appComponentName =
             ComponentName(
                 InstrumentationRegistry.getInstrumentation().context.packageName,
-                TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
+                TEST_ACTIVITY_PACKAGE_PREFIX + testAppName,
             )
     }
 
@@ -92,7 +92,7 @@
     private fun addCorrespondingWidgetRect(
         widgetRect: WidgetRect,
         transaction: FavoriteItemsTransaction,
-        screenId: Int
+        screenId: Int,
     ) {
         if (widgetRect.type == 'x') {
             fillWithWidgets(widgetRect, transaction, screenId)
@@ -105,7 +105,7 @@
     fun buildFromBoard(
         board: CellLayoutBoard,
         transaction: FavoriteItemsTransaction,
-        screenId: Int
+        screenId: Int,
     ): FavoriteItemsTransaction {
         board.widgets.forEach { addCorrespondingWidgetRect(it, transaction, screenId) }
         board.icons.forEach { transaction.addItem { createIconInCell(it, screenId) } }
@@ -130,7 +130,7 @@
             WidgetUtils.createWidgetInfo(
                     TestViewHelpers.findWidgetProvider(false),
                     ApplicationProvider.getApplicationContext(),
-                    true
+                    true,
                 )
                 .apply {
                     cellX = widgetRect.cellX
@@ -154,7 +154,7 @@
             minSpanY = 1
             setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null)
             for (i in 0 until folderPoint.numberIconsInside) {
-                add(getDefaultWorkspaceItem(paramScreenId), false)
+                add(getDefaultWorkspaceItem(paramScreenId))
             }
         }
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
index bcf5f0d..e825995 100644
--- a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
@@ -298,12 +298,13 @@
         val dragObject = DragObject(context)
         dragObject.dragInfo = Mockito.mock(ItemInfo::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         dragObject.dragSource = folder
 
         folder.onDragStart(dragObject, DragOptions())
 
         verify(folder.mContent, times(1)).removeItem(folder.currentDragView)
-        verify(folder.mInfo, times(1)).remove(dragObject.dragInfo, true)
+        verify(folder, times(1)).removeFolderContent(true, dragObject.dragInfo)
         assertTrue(folder.itemsInvalidated)
         assertTrue(folder.isDragInProgress)
         assertFalse(folder.itemAddedBackToSelfViaIcon)
@@ -827,19 +828,19 @@
 
     @Test
     fun `onRemove should call removeItem with the correct views`() {
+        val folderInfo =
+            workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+        val items = folderInfo.getContents().toTypedArray()
+        folder.mInfo = folderInfo
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
-        val items =
-            arrayListOf<ItemInfo>(
-                Mockito.mock(ItemInfo::class.java),
-                Mockito.mock(ItemInfo::class.java),
-            )
         val view1 = Mockito.mock(View::class.java)
         val view2 = Mockito.mock(View::class.java)
         doReturn(view1).whenever(folder).getViewForInfo(items[0])
         doReturn(view2).whenever(folder).getViewForInfo(items[1])
         doReturn(2).whenever(folder).itemCount
 
-        folder.onRemove(items)
+        folder.removeFolderContent(false, *items)
 
         verify(folder.mContent, times(1)).removeItem(view1)
         verify(folder.mContent, times(1)).removeItem(view2)
@@ -847,20 +848,20 @@
 
     @Test
     fun `onRemove should set mRearrangeOnClose to true and not call rearrangeChildren if animating`() {
+        val folderInfo =
+            workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+        val items = folderInfo.getContents().toTypedArray()
+        folder.mInfo = folderInfo
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
         folder.state = STATE_ANIMATING
-        val items =
-            arrayListOf<ItemInfo>(
-                Mockito.mock(ItemInfo::class.java),
-                Mockito.mock(ItemInfo::class.java),
-            )
         val view1 = Mockito.mock(View::class.java)
         val view2 = Mockito.mock(View::class.java)
         doReturn(view1).whenever(folder).getViewForInfo(items[0])
         doReturn(view2).whenever(folder).getViewForInfo(items[1])
         doReturn(2).whenever(folder).itemCount
 
-        folder.onRemove(items)
+        folder.removeFolderContent(true, *items)
 
         assertTrue(folder.rearrangeOnClose)
         verify(folder, times(0)).rearrangeChildren()
@@ -868,21 +869,21 @@
 
     @Test
     fun `onRemove should set not change mRearrangeOnClose and not call rearrangeChildren if not animating`() {
+        val folderInfo =
+            workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+        val items = folderInfo.getContents().toTypedArray()
+        folder.mInfo = folderInfo
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
         folder.state = STATE_CLOSED
         folder.rearrangeOnClose = false
-        val items =
-            arrayListOf<ItemInfo>(
-                Mockito.mock(ItemInfo::class.java),
-                Mockito.mock(ItemInfo::class.java),
-            )
         val view1 = Mockito.mock(View::class.java)
         val view2 = Mockito.mock(View::class.java)
         doReturn(view1).whenever(folder).getViewForInfo(items[0])
         doReturn(view2).whenever(folder).getViewForInfo(items[1])
         doReturn(2).whenever(folder).itemCount
 
-        folder.onRemove(items)
+        folder.removeFolderContent(false, *items)
 
         assertFalse(folder.rearrangeOnClose)
         verify(folder, times(1)).rearrangeChildren()
@@ -890,12 +891,12 @@
 
     @Test
     fun `onRemove should call close if mIsOpen is true and item count is less than or equal to one`() {
+        val folderInfo =
+            workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+        val items = folderInfo.getContents().toTypedArray()
+        folder.mInfo = folderInfo
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
-        val items =
-            arrayListOf<ItemInfo>(
-                Mockito.mock(ItemInfo::class.java),
-                Mockito.mock(ItemInfo::class.java),
-            )
         val view1 = Mockito.mock(View::class.java)
         val view2 = Mockito.mock(View::class.java)
         doReturn(view1).whenever(folder).getViewForInfo(items[0])
@@ -904,19 +905,19 @@
         folder.setIsOpen(true)
         doNothing().`when`(folder).close(true)
 
-        folder.onRemove(items)
+        folder.removeFolderContent(false, *items)
 
         verify(folder, times(1)).close(true)
     }
 
     @Test
     fun `onRemove should call replaceFolderWithFinalItem if mIsOpen is false and item count is less than or equal to one`() {
+        val folderInfo =
+            workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+        val items = folderInfo.getContents().toTypedArray()
+        folder.mInfo = folderInfo
+        folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
         folder.mContent = Mockito.mock(FolderPagedView::class.java)
-        val items =
-            arrayListOf<ItemInfo>(
-                Mockito.mock(ItemInfo::class.java),
-                Mockito.mock(ItemInfo::class.java),
-            )
         val view1 = Mockito.mock(View::class.java)
         val view2 = Mockito.mock(View::class.java)
         doReturn(view1).whenever(folder).getViewForInfo(items[0])
@@ -924,7 +925,7 @@
         doReturn(1).whenever(folder).itemCount
         folder.setIsOpen(false)
 
-        folder.onRemove(items)
+        folder.removeFolderContent(false, *items)
 
         verify(folder, times(1)).replaceFolderWithFinalItem()
     }
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 08b8f81..25f4cf1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -33,7 +33,6 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.same
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.verifyNoMoreInteractions
 import org.mockito.kotlin.whenever
@@ -142,10 +141,9 @@
     /** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */
     private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) {
         val spaceStack = newItemSpaces.toMutableList()
-        whenever(
-                mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any(), any(), any())
-            )
-            .then { spaceStack.removeFirst().toIntArray() }
+        whenever(mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any())).then {
+            spaceStack.removeFirst().toIntArray()
+        }
     }
 
     /**
@@ -155,8 +153,6 @@
     private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
         verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
             .findSpaceForItem(
-                eq(mAppState),
-                same(mModelHelper.bgDataModel),
                 eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
                 eq(IntArray()),
                 eq(1),
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
index 09752b8..89e676f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
@@ -11,6 +11,7 @@
 import com.android.launcher3.LauncherSettings.Favorites.addTableToDb
 import com.android.launcher3.pm.UserCache
 import com.android.launcher3.provider.LauncherDbUtils
+import com.android.launcher3.util.ModelTestExtensions
 import java.util.function.ToLongFunction
 import org.junit.After
 import org.junit.Assert.assertEquals
@@ -33,7 +34,7 @@
 
     @Before
     fun setUp() {
-        db = FactitiousDbController(context, INSERTION_SQL).inMemoryDb
+        db = ModelTestExtensions.createInMemoryDb(INSERTION_SQL)
     }
 
     @After
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt b/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt
deleted file mode 100644
index 711e1d2..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.android.launcher3.model
-
-import android.content.Context
-import android.database.Cursor
-import android.database.sqlite.SQLiteDatabase
-import androidx.test.platform.app.InstrumentationRegistry
-import java.io.BufferedReader
-import java.io.InputStreamReader
-
-private val All_COLUMNS =
-    arrayOf(
-        "_id",
-        "title",
-        "intent",
-        "container",
-        "screen",
-        "cellX",
-        "cellY",
-        "spanX",
-        "spanY",
-        "itemType",
-        "appWidgetId",
-        "icon",
-        "appWidgetProvider",
-        "modified",
-        "restored",
-        "profileId",
-        "rank",
-        "options",
-        "appWidgetSource"
-    )
-
-class FactitiousDbController(context: Context, insertFile: String) : ModelDbController(context) {
-
-    val inMemoryDb: SQLiteDatabase by lazy {
-        SQLiteDatabase.createInMemory(SQLiteDatabase.OpenParams.Builder().build()).also { db ->
-            BufferedReader(
-                    InputStreamReader(
-                        InstrumentationRegistry.getInstrumentation().context.assets.open(insertFile)
-                    )
-                )
-                .lines()
-                .forEach { sqlStatement -> db.execSQL(sqlStatement) }
-        }
-    }
-
-    override fun query(
-        table: String,
-        projection: Array<out String>?,
-        selection: String?,
-        selectionArgs: Array<out String>?,
-        sortOrder: String?
-    ): Cursor {
-        return inMemoryDb.query(table, All_COLUMNS, selection, selectionArgs, null, null, sortOrder)
-    }
-
-    override fun loadDefaultFavoritesIfNecessary() {
-        // No-Op
-    }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index ad40818..b848d27 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -55,7 +55,6 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.database.MatrixCursor;
 import android.graphics.Bitmap;
@@ -76,6 +75,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LauncherModelHelper;
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
 import com.android.launcher3.util.PackageManagerHelper;
 
 import org.junit.After;
@@ -96,11 +96,10 @@
 
     private LauncherModelHelper mModelHelper;
     private LauncherAppState mApp;
-    private PackageManagerHelper mPmHelper;
 
     private MatrixCursor mCursor;
     private InvariantDeviceProfile mIDP;
-    private Context mContext;
+    private SandboxModelContext mContext;
 
     private LoaderCursor mLoaderCursor;
 
@@ -116,7 +115,6 @@
         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,
@@ -126,7 +124,8 @@
         });
 
         UserManagerState ums = new UserManagerState();
-        mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, mPmHelper, null);
+        mLoaderCursor = mContext.getAppComponent().getLoaderCursorFactory()
+                .createLoaderCursor(mCursor, ums, null);
         ums.allUsers.put(0, Process.myUserHandle());
     }
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
index eec6eed..5fd93d1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
@@ -27,8 +27,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.AppFilter
 import com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
 import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.PackageUpdatedTask.OP_ADD
 import com.android.launcher3.model.PackageUpdatedTask.OP_REMOVE
@@ -39,17 +40,20 @@
 import com.android.launcher3.model.PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE
 import com.android.launcher3.model.data.AppInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.AllModulesForTest
 import com.android.launcher3.util.Executors
 import com.android.launcher3.util.LauncherModelHelper
-import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
 import com.android.launcher3.util.TestUtil
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
@@ -61,10 +65,8 @@
     @get:Rule val setFlagsRule = SetFlagsRule()
 
     private val mUser = myUserHandle()
-    private val mDataModel: BgDataModel = BgDataModel()
     private val mLauncherModelHelper = LauncherModelHelper()
-    private val mContext: SandboxModelContext = spy(mLauncherModelHelper.sandboxContext)
-    private val mAppState: LauncherAppState = spy(LauncherAppState.getInstance(mContext))
+    private val mContext = mLauncherModelHelper.sandboxContext
 
     private val expectedPackage = "Test.Package"
     private val expectedComponent = ComponentName(expectedPackage, "TestClass")
@@ -72,22 +74,33 @@
     private val expectedWorkspaceItem = spy(WorkspaceItemInfo())
 
     private val mockIconCache: IconCache = mock()
-    private val mockTaskController: ModelTaskController = mock<ModelTaskController>()
     private val mockAppFilter: AppFilter = mock<AppFilter>()
+    private lateinit var mAllAppsList: AllAppsList
+
     private val mockApplicationInfo: ApplicationInfo = mock<ApplicationInfo>()
     private val mockActivityInfo: ActivityInfo = mock<ActivityInfo>()
 
-    private lateinit var mAllAppsList: AllAppsList
+    private lateinit var mDataModel: BgDataModel
+    private lateinit var mockTaskController: ModelTaskController
 
     @Before
     fun setup() {
         mAllAppsList = spy(AllAppsList(mockIconCache, mockAppFilter))
-        mLauncherModelHelper.sandboxContext.spyService(LauncherApps::class.java).apply {
+        mContext.initDaggerComponent(
+            DaggerPackageUpdatedTaskTest_TestComponent.builder()
+                .bindAllAppsList(mAllAppsList)
+                .bindAppFilter(mockAppFilter)
+                .bindIconCache(mockIconCache)
+        )
+
+        mContext.spyService(LauncherApps::class.java).apply {
             whenever(getActivityList(expectedPackage, mUser))
                 .thenReturn(listOf(expectedActivityInfo))
         }
-        whenever(mAppState.iconCache).thenReturn(mockIconCache)
-        whenever(mockTaskController.app).thenReturn(mAppState)
+
+        mockTaskController = spy((mContext.appComponent as TestComponent).getTaskController())
+        mDataModel = (mContext.appComponent as TestComponent).getDataModel()
+
         whenever(mockAppFilter.shouldShowApp(expectedComponent)).thenReturn(true)
         mockApplicationInfo.apply {
             uid = 1
@@ -122,7 +135,6 @@
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser)
         verify(mAllAppsList).addPackage(mContext, expectedPackage, mUser)
@@ -141,7 +153,6 @@
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser)
         verify(mAllAppsList).updatePackage(mContext, expectedPackage, mUser)
@@ -159,7 +170,6 @@
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mockIconCache).removeIconsForPkg(expectedPackage, mUser)
         verify(mAllAppsList).removePackage(expectedPackage, mUser)
@@ -176,7 +186,6 @@
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mAllAppsList).removePackage(expectedPackage, mUser)
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
@@ -190,10 +199,11 @@
         // When
         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
         mAllAppsList.add(AppInfo(mContext, expectedActivityInfo, mUser), expectedActivityInfo)
+        mAllAppsList.getAndResetChangeFlag()
+        doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded()
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mAllAppsList).updateDisabledFlags(any(), any())
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
@@ -206,10 +216,11 @@
         val taskUnderTest = PackageUpdatedTask(OP_UNSUSPEND, mUser, expectedPackage)
         // When
         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
+        mAllAppsList.getAndResetChangeFlag()
+        doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded()
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mAllAppsList).updateDisabledFlags(any(), any())
         verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList())
@@ -226,10 +237,29 @@
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
         }
-        mLauncherModelHelper.loadModelSync()
         // Then
         verify(mAllAppsList).updateDisabledFlags(any(), any())
         verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList())
         assertThat(mAllAppsList.data).isEmpty()
     }
+
+    @LauncherAppSingleton
+    @Component(modules = [AllModulesForTest::class])
+    interface TestComponent : LauncherAppComponent {
+
+        fun getDataModel(): BgDataModel
+
+        fun getTaskController(): ModelTaskController
+
+        @Component.Builder
+        interface Builder : LauncherAppComponent.Builder {
+            @BindsInstance fun bindAppFilter(appFilter: AppFilter): Builder
+
+            @BindsInstance fun bindIconCache(iconCache: IconCache): Builder
+
+            @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder
+
+            override fun build(): TestComponent
+        }
+    }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt
index c6863f4..0ab736b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt
@@ -30,7 +30,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.launcher3.Flags
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
 import com.android.launcher3.icons.BitmapInfo
 import com.android.launcher3.icons.CacheableShortcutInfo
@@ -73,7 +72,6 @@
     private val user: UserHandle = myUserHandle()
     private val mockTaskController: ModelTaskController = mock()
     private val mockAllApps: AllAppsList = mock()
-    private val mockAppState: LauncherAppState = mock()
     private val mockIconCache: IconCache = mock()
 
     private val expectedWai =
@@ -93,9 +91,8 @@
         modelHelper.loadModelSync()
         context = modelHelper.sandboxContext
         launcherApps = context.spyService(LauncherApps::class.java)
-        whenever(mockTaskController.app).thenReturn(mockAppState)
-        whenever(mockAppState.context).thenReturn(context)
-        whenever(mockAppState.iconCache).thenReturn(mockIconCache)
+        whenever(mockTaskController.context).thenReturn(context)
+        whenever(mockTaskController.iconCache).thenReturn(mockIconCache)
         whenever(mockIconCache.getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()))
             .then { _ -> { expectedWai.bitmap = BitmapInfo.LOW_RES_INFO } }
         shortcuts = emptyList()
@@ -132,8 +129,7 @@
         // When
         shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps)
         // Then
-        verify(mockAppState.iconCache)
-            .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
+        verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai))
     }
 
@@ -196,8 +192,7 @@
         // When
         shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps)
         // Then
-        verify(mockAppState.iconCache)
-            .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
+        verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai))
     }
 
@@ -256,8 +251,7 @@
         // When
         shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps)
         // Then
-        verify(mockAppState.iconCache)
-            .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
+        verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai))
     }
 
@@ -287,8 +281,7 @@
         // When
         shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps)
         // Then
-        verify(mockAppState.iconCache)
-            .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
+        verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())
         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai))
     }
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
index 777d81b..2e6ecc5 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
@@ -25,9 +25,9 @@
 import android.platform.test.rule.LimitDevicesRule
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.AppFilter
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.InvariantDeviceProfile
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.data.PackageItemInfo
 import com.android.launcher3.pm.UserCache
@@ -62,7 +62,6 @@
     @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
 
     @Mock private lateinit var appWidgetManager: AppWidgetManager
-    @Mock private lateinit var app: LauncherAppState
     @Mock private lateinit var iconCacheMock: IconCache
 
     private lateinit var context: Context
@@ -93,9 +92,6 @@
 
         whenever(iconCacheMock.getTitleNoCache(any<LauncherAppWidgetProviderInfo>()))
             .thenReturn("title")
-        whenever(app.iconCache).thenReturn(iconCacheMock)
-        whenever(app.context).thenReturn(context)
-        whenever(app.invariantDeviceProfile).thenReturn(idp)
 
         val widgetToCategoryEntry: Map.Entry<ComponentName, IntSet> =
             WidgetSections.getWidgetsToCategory(context).entries.first()
@@ -128,7 +124,7 @@
         val userCache = spy(UserCache.INSTANCE.get(context))
         whenever(userCache.userProfiles).thenReturn(listOf(UserHandle.CURRENT))
 
-        underTest = WidgetsModel()
+        underTest = WidgetsModel(context, idp, iconCacheMock, AppFilter(context))
     }
 
     @Test
@@ -237,7 +233,7 @@
                     update = false
                     // Similarly, model could update its code independently while a client is
                     // iterating on the list.
-                    underTest.update(app, /* packageUser= */ null)
+                    underTest.update(/* packageUser= */ null)
                 }
             }
 
@@ -253,7 +249,7 @@
     private fun loadWidgets() {
         val latch = CountDownLatch(1)
         Executors.MODEL_EXECUTOR.execute {
-            underTest.update(app, /* packageUser= */ null)
+            underTest.update(/* packageUser= */ null)
             latch.countDown()
         }
         if (!latch.await(LOAD_WIDGETS_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index a55d64b..cba7b88 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -31,7 +31,7 @@
 import android.util.LongSparseArray
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.Flags
-import com.android.launcher3.LauncherAppState
+import com.android.launcher3.InvariantDeviceProfile
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
@@ -41,6 +41,7 @@
 import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
 import com.android.launcher3.icons.CacheableShortcutInfo
+import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.ItemInfo
@@ -66,12 +67,14 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Answers
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.RETURNS_DEEP_STUBS
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doAnswer
@@ -88,12 +91,12 @@
     @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
     @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
     @Mock private lateinit var mockBgDataModel: BgDataModel
-    @Mock private lateinit var mockAppState: LauncherAppState
     @Mock private lateinit var mockPmHelper: PackageManagerHelper
-    @Mock private lateinit var mockCursor: LoaderCursor
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var mockCursor: LoaderCursor
     @Mock private lateinit var mockUserCache: UserCache
     @Mock private lateinit var mockUserManagerState: UserManagerState
     @Mock private lateinit var mockWidgetInflater: WidgetInflater
+    @Mock private lateinit var mockIconCache: IconCache
 
     lateinit var mModelHelper: LauncherModelHelper
     lateinit var mContext: SandboxModelContext
@@ -114,6 +117,7 @@
 
     @Before
     fun setup() {
+        MockitoAnnotations.initMocks(this)
         mModelHelper = LauncherModelHelper()
         mContext = mModelHelper.sandboxContext
         mLauncherApps =
@@ -122,9 +126,6 @@
                 doReturn(true).whenever(this).isActivityEnabled(mComponentName, mUserHandle)
             }
         mUserHandle = Process.myUserHandle()
-        mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
-        mockWorkspaceInfo = mock<WorkspaceItemInfo>()
-        mockBgDataModel = mock<BgDataModel>()
         mComponentName = ComponentName("package", "class")
         mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
         mIntent =
@@ -133,40 +134,26 @@
                 `package` = "pkg"
                 putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
             }
-        mockAppState =
-            mock<LauncherAppState>().apply {
-                whenever(context).thenReturn(mContext)
-                whenever(iconCache).thenReturn(mock())
-                whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
-            }
-        mockPmHelper =
-            mock<PackageManagerHelper>().apply {
-                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
-                    .thenReturn(mIntent)
-            }
-        mockCursor =
-            mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
-                user = mUserHandle
-                itemType = ITEM_TYPE_APPLICATION
-                id = 1
-                restoreFlag = 1
-                serialNumber = 101
-                whenever(parseIntent()).thenReturn(mIntent)
-                whenever(markRestored()).doAnswer { restoreFlag = 0 }
-                whenever(updater().put(Favorites.INTENT, mIntent.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)
-            }
+        whenever(mockIconCache.getShortcutIcon(any(), any(), any())).then {}
+        whenever(mockPmHelper.getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+            .thenReturn(mIntent)
+        mockCursor.apply {
+            user = mUserHandle
+            itemType = ITEM_TYPE_APPLICATION
+            id = 1
+            restoreFlag = 1
+            serialNumber = 101
+            whenever(parseIntent()).thenReturn(mIntent)
+            whenever(markRestored()).doAnswer { restoreFlag = 0 }
+            whenever(updater().put(Favorites.INTENT, mIntent.toUri(0)).commit()).thenReturn(1)
+            whenever(getAppShortcutInfo(any(), any(), any(), any())).thenReturn(mockWorkspaceInfo)
+            whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
+        }
+        mockUserCache.apply {
+            val userIconInfo = mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
+            whenever(getUserInfo(any())).thenReturn(userIconInfo)
+        }
 
-        mockUserManagerState = mock<UserManagerState>()
-        mockWidgetInflater = mock<WidgetInflater>()
         mKeyToPinnedShortcutsMap = mutableMapOf()
         mInstallingPkgs = hashMapOf()
         mAllDeepShortcuts = mutableListOf()
@@ -187,7 +174,6 @@
         userManagerState: UserManagerState = mockUserManagerState,
         launcherApps: LauncherApps = mLauncherApps,
         shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
-        app: LauncherAppState = mockAppState,
         bgDataModel: BgDataModel = mockBgDataModel,
         widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
         widgetInflater: WidgetInflater = mockWidgetInflater,
@@ -205,7 +191,7 @@
             userCache = userCache,
             userManagerState = userManagerState,
             launcherApps = launcherApps,
-            app = app,
+            context = mContext,
             bgDataModel = bgDataModel,
             widgetProvidersMap = widgetProvidersMap,
             widgetInflater = widgetInflater,
@@ -217,6 +203,9 @@
             shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
             installingPkgs = installingPkgs,
             allDeepShortcuts = allDeepShortcuts,
+            iconCache = mockIconCache,
+            idp = InvariantDeviceProfile.INSTANCE.get(mContext),
+            isSafeMode = false,
         )
 
     @Test
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index dd03eee..a18f93b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -29,8 +29,6 @@
 @RunWith(AndroidJUnit4::class)
 class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
 
-    private val mItemSpaceFinder = WorkspaceItemSpaceFinder()
-
     @Before
     override fun setup() {
         super.setup()
@@ -42,15 +40,12 @@
     }
 
     private fun findSpace(spanX: Int, spanY: Int): NewItemSpace =
-        mItemSpaceFinder
-            .findSpaceForItem(
-                mAppState,
+        WorkspaceItemSpaceFinder(
                 mModelHelper.bgDataModel,
-                mExistingScreens,
-                mNewScreens,
-                spanX,
-                spanY,
+                mAppState.invariantDeviceProfile,
+                mModelHelper.model,
             )
+            .findSpaceForItem(mExistingScreens, mNewScreens, spanX, spanY)
             .let { NewItemSpace.fromIntArray(it) }
 
     private fun assertRegionVacant(newItemSpace: NewItemSpace, spanX: Int, spanY: Int) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index c30b730..0f4940e 100644
--- a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -24,8 +24,6 @@
 import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -50,7 +48,6 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.util.LongSparseArray;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -60,9 +57,17 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.model.ModelDbController;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.AllModulesForTest;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LauncherModelHelper;
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
+
+import dagger.BindsInstance;
+import dagger.Component;
 
 import org.junit.After;
 import org.junit.Before;
@@ -85,7 +90,9 @@
     private final UserHandle mWorkUser = UserHandle.getUserHandleForUid(PER_USER_RANGE);
 
     private LauncherModelHelper mModelHelper;
-    private Context mContext;
+    private SandboxModelContext mContext;
+    private UserCache mUserCacheSpy;
+
     private RestoreDbTask mTask;
     private ModelDbController mMockController;
     private SQLiteDatabase mMockDb;
@@ -94,10 +101,17 @@
     private LauncherRestoreEventLogger mMockRestoreEventLogger;
     private SQLiteDatabase mDb;
 
+    private AppWidgetHost mWidgetHost;
+
     @Before
     public void setup() {
         mModelHelper = new LauncherModelHelper();
         mContext = mModelHelper.sandboxContext;
+        mUserCacheSpy = spy(UserCache.getInstance(getInstrumentation().getTargetContext()));
+
+        mContext.initDaggerComponent(
+                DaggerRestoreDbTaskTest_TestComponent.builder().bindUserCache(mUserCacheSpy));
+
         mTask = new RestoreDbTask();
         mMockController = Mockito.mock(ModelDbController.class);
         mMockDb = mock(SQLiteDatabase.class);
@@ -106,24 +120,34 @@
         mMockRestoreEventLogger = mock(LauncherRestoreEventLogger.class);
     }
 
+    private synchronized AppWidgetHost getWidgetHostLazy() {
+        if (mWidgetHost == null) {
+            mWidgetHost = new AppWidgetHost(mContext, 1012);
+        }
+        return mWidgetHost;
+    }
+
     @After
     public void teardown() {
         if (mDb != null) {
             mDb.close();
         }
+        if (mWidgetHost != null) {
+            mWidgetHost.deleteHost();
+        }
         mModelHelper.destroy();
         LauncherPrefs.get(mContext).removeSync(RESTORE_DEVICE);
     }
 
     @Test
     public void testGetProfileId() throws Exception {
-        mDb = new MyModelDbController(23).getDb();
+        mDb = getModelDbController(23).getDb();
         assertEquals(23, new RestoreDbTask().getDefaultProfileId(mDb));
     }
 
     @Test
     public void testMigrateProfileId() throws Exception {
-        mDb = new MyModelDbController(42).getDb();
+        mDb = getModelDbController(42).getDb();
         // Add some mock data
         for (int i = 0; i < 5; i++) {
             ContentValues values = new ContentValues();
@@ -143,7 +167,7 @@
 
     @Test
     public void testChangeDefaultColumn() throws Exception {
-        mDb = new MyModelDbController(42).getDb();
+        mDb = getModelDbController(42).getDb();
         // Add some mock data
         for (int i = 0; i < 5; i++) {
             ContentValues values = new ContentValues();
@@ -173,12 +197,12 @@
         long workProfileId = myProfileId + 2;
         long workProfileId_old = myProfileId + 3;
 
-        MyModelDbController controller = new MyModelDbController(myProfileId);
+        ModelDbController controller = getModelDbController(myProfileId);
         mDb = controller.getDb();
         BackupManager bm = spy(new BackupManager(mContext));
         doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old));
         doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old));
-        controller.users.put(workProfileId, mWorkUser);
+        doReturn(workProfileId).when(mUserCacheSpy).getSerialNumberForUser(mWorkUser);
 
         addIconsBulk(controller, 10, 1, myProfileId_old);
         addIconsBulk(controller, 6, 2, workProfileId_old);
@@ -202,7 +226,7 @@
         long myProfileId_old = myProfileId + 1;
         long workProfileId_old = myProfileId + 3;
 
-        MyModelDbController controller = new MyModelDbController(myProfileId);
+        ModelDbController controller = getModelDbController(myProfileId);
         mDb = controller.getDb();
         BackupManager bm = spy(new BackupManager(mContext));
         doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old));
@@ -226,7 +250,8 @@
     @Test
     public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() {
         // When
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger,
+                this::getWidgetHostLazy);
         // Then
         assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
     }
@@ -234,7 +259,7 @@
     @Test
     public void givenNoPendingRestore_WhenRestoreAppWidgetIds_ThenRemoveNewWidgetIds() {
         // Given
-        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        AppWidgetHost expectedHost = getWidgetHostLazy();
         int[] expectedOldIds = generateOldWidgetIds(expectedHost);
         int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
         when(mMockController.getDb()).thenReturn(mMockDb);
@@ -242,7 +267,8 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger,
+                this::getWidgetHostLazy);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -254,7 +280,7 @@
     @Test
     public void givenRestoreWithNonExistingWidgets_WhenRestoreAppWidgetIds_ThenRemoveNewIds() {
         // Given
-        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        AppWidgetHost expectedHost = getWidgetHostLazy();
         int[] expectedOldIds = generateOldWidgetIds(expectedHost);
         int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
         when(mMockController.getDb()).thenReturn(mMockDb);
@@ -265,18 +291,19 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger,
+                this::getWidgetHostLazy);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
         assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
-        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any());
+        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any());
     }
 
     @Test
     public void givenRestore_WhenRestoreAppWidgetIds_ThenAddNewIds() {
         // Given
-        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        AppWidgetHost expectedHost = getWidgetHostLazy();
         int[] expectedOldIds = generateOldWidgetIds(expectedHost);
         int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
         int[] allExpectedIds = IntStream.concat(
@@ -294,15 +321,16 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger,
+                this::getWidgetHostLazy);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds);
         assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
-        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any());
+        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any());
     }
 
-    private void addIconsBulk(MyModelDbController controller,
+    private void addIconsBulk(ModelDbController controller,
             int count, int screen, long profileId) {
         int columns = LauncherAppState.getIDP(mContext).numColumns;
         String packageName = getInstrumentation().getContext().getPackageName();
@@ -320,7 +348,7 @@
             values.put(LauncherSettings.Favorites.INTENT,
                     new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0));
 
-            controller.insert(TABLE_NAME, values);
+            controller.insert(values);
         }
     }
 
@@ -346,7 +374,7 @@
     }
 
     private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) {
-        mDb = new MyModelDbController(42).getDb();
+        mDb = getModelDbController(42).getDb();
         // Add some mock data
         for (int i = 0; i < screenIds.length; i++) {
             ContentValues values = new ContentValues();
@@ -397,25 +425,29 @@
                 .map(id -> host.allocateAppWidgetId()).toArray();
     }
 
-    private class MyModelDbController extends ModelDbController {
-
-        public final LongSparseArray<UserHandle> users = new LongSparseArray<>();
-
-        MyModelDbController(long profileId) {
-            super(mContext);
-            users.put(profileId, myUserHandle());
-        }
-
-        @Override
-        public long getSerialNumberForUser(UserHandle user) {
-            int index = users.indexOfValue(user);
-            return index >= 0 ? users.keyAt(index) : -1;
-        }
-    }
-
     private void setRestoredAppWidgetIds(Context context, int[] oldIds, int[] newIds) {
         LauncherPrefs.get(context).putSync(
                 OLD_APP_WIDGET_IDS.to(IntArray.wrap(oldIds).toConcatString()),
                 APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString()));
     }
+
+    private ModelDbController getModelDbController(long profileId) {
+        doReturn(profileId).when(mUserCacheSpy).getSerialNumberForUser(myUserHandle());
+        return ((TestComponent) mContext.getAppComponent()).getDbController();
+    }
+
+    @LauncherAppSingleton
+    @Component(modules = AllModulesForTest.class)
+    public interface TestComponent extends LauncherAppComponent {
+
+        ModelDbController getDbController();
+
+        @Component.Builder
+        interface Builder extends LauncherAppComponent.Builder {
+
+            @BindsInstance Builder bindUserCache(UserCache userCache);
+
+            TestComponent build();
+        }
+    }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
index ceefb0d..524acff 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -1,10 +1,11 @@
 package com.android.launcher3.util
 
 import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
 import android.os.Process
+import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.Flags
 import com.android.launcher3.LauncherModel
-import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID
 import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER
 import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE
@@ -24,6 +25,8 @@
 import com.android.launcher3.LauncherSettings.Favorites._ID
 import com.android.launcher3.model.BgDataModel
 import com.android.launcher3.model.ModelDbController
+import java.io.BufferedReader
+import java.io.InputStreamReader
 
 object ModelTestExtensions {
     /** Clears and reloads Launcher db to cleanup the workspace */
@@ -68,7 +71,6 @@
         spanY: Int = 1,
         id: Int = 0,
         profileId: Int = Process.myUserHandle().identifier,
-        tableName: String = Favorites.TABLE_NAME,
         appWidgetId: Int = -1,
         appWidgetSource: Int = -1,
         appWidgetProvider: String? = null,
@@ -97,9 +99,21 @@
                         values[APPWIDGET_PROVIDER] = appWidgetProvider
                     }
                 // Migrate any previous data so that the DB state is correct
-                controller.insert(tableName, values)
+                controller.insert(values)
                 transaction.commit()
             }
         }
     }
+
+    /** Creates an in-memory sqlite DB and initializes with the data in [insertFile] */
+    fun createInMemoryDb(insertFile: String): SQLiteDatabase =
+        SQLiteDatabase.createInMemory(SQLiteDatabase.OpenParams.Builder().build()).also { db ->
+            BufferedReader(
+                    InputStreamReader(
+                        InstrumentationRegistry.getInstrumentation().context.assets.open(insertFile)
+                    )
+                )
+                .lines()
+                .forEach { sqlStatement -> db.execSQL(sqlStatement) }
+        }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
index 17933f2..97651d3 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
@@ -127,6 +127,29 @@
     }
 
     @Test
+    fun sync_register_withCompletionRunnable_and_permission_and_flag() {
+        underTest =
+            SimpleBroadcastReceiver(context, Handler(Looper.getMainLooper()), intentConsumer)
+
+        underTest.register(completionRunnable, "permission", 1, "test_action_1", "test_action_2")
+        getInstrumentation().waitForIdleSync()
+
+        verify(context)
+            .registerReceiver(
+                same(underTest),
+                intentFilterCaptor.capture(),
+                eq("permission"),
+                eq(null),
+                eq(1),
+            )
+        verify(completionRunnable).run()
+        val intentFilter = intentFilterCaptor.value
+        assertThat(intentFilter.countActions()).isEqualTo(2)
+        assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+        assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+    }
+
+    @Test
     fun async_unregister() {
         underTest.unregisterReceiverSafely()
 
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
index 38fad6b..34d9d40 100644
--- a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -23,8 +23,8 @@
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.launcher3.Flags
+import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherPrefs
-import com.android.launcher3.model.ModelDbController
 import com.android.launcher3.model.ModelDelegate
 import com.android.launcher3.provider.RestoreDbTask
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
@@ -45,11 +45,8 @@
 @MediumTest
 class BackupAndRestoreDBSelectionTest {
 
-    @JvmField @Rule var backAndRestoreRule = BackAndRestoreRule()
-
-    @JvmField
-    @Rule
-    val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+    @get:Rule var backAndRestoreRule = BackAndRestoreRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     val modelDelegate = mock<ModelDelegate>()
 
@@ -70,7 +67,8 @@
 
     @Test
     fun oldDatabasesNotPresentAfterRestore() {
-        val dbController = ModelDbController(getInstrumentation().targetContext)
+        val dbController =
+            LauncherAppState.getInstance(getInstrumentation().targetContext).model.modelDbController
         if (Flags.gridMigrationRefactor()) {
             dbController.attemptMigrateDb(null, modelDelegate)
         } else {
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 246219f..560d306 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -5,6 +5,7 @@
 import android.content.Intent
 import android.content.pm.ApplicationInfo
 import android.content.pm.LauncherActivityInfo
+import android.database.sqlite.SQLiteDatabase
 import android.os.Process
 import android.os.UserHandle
 import android.platform.test.annotations.DisableFlags
@@ -16,7 +17,6 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
 import com.android.launcher3.Flags
-import com.android.launcher3.LauncherAppState
 import com.android.launcher3.LauncherModel
 import com.android.launcher3.LauncherModel.LoaderTransaction
 import com.android.launcher3.LauncherPrefs
@@ -26,11 +26,13 @@
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
 import com.android.launcher3.dagger.LauncherAppComponent
 import com.android.launcher3.dagger.LauncherAppSingleton
 import com.android.launcher3.icons.IconCache
 import com.android.launcher3.icons.cache.CachingLogic
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
+import com.android.launcher3.model.LoaderTask.LoaderTaskFactory
 import com.android.launcher3.model.data.AppInfo
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -41,9 +43,9 @@
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
 import com.android.launcher3.util.LooperIdleLock
+import com.android.launcher3.util.ModelTestExtensions
 import com.android.launcher3.util.TestUtil
 import com.android.launcher3.util.UserIconInfo
-import com.google.common.truth.Truth
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
@@ -57,7 +59,6 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.mock
 import org.mockito.Mockito.times
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
@@ -65,6 +66,7 @@
 import org.mockito.Spy
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
@@ -93,26 +95,33 @@
 
     @Mock private lateinit var bgAllAppsList: AllAppsList
     @Mock private lateinit var modelDelegate: ModelDelegate
-    @Mock private lateinit var launcherBinder: BaseLauncherBinder
-    private lateinit var launcherModel: LauncherModel
-    @Mock private lateinit var transaction: LoaderTransaction
+    @Mock private lateinit var launcherModel: LauncherModel
     @Mock private lateinit var iconCache: IconCache
+    @Mock private lateinit var userCache: UserCache
+    @Mock private lateinit var modelDbController: ModelDbController
+
+    @Mock private lateinit var launcherBinder: BaseLauncherBinder
+    @Mock private lateinit var transaction: LoaderTransaction
     @Mock private lateinit var idleLock: LooperIdleLock
     @Mock private lateinit var iconCacheUpdateHandler: IconCacheUpdateHandler
-    @Mock private lateinit var userCache: UserCache
 
-    @Spy private var userManagerState: UserManagerState? = UserManagerState()
+    @Spy private var userManagerState: UserManagerState = UserManagerState()
 
     @get:Rule val setFlagsRule = SetFlagsRule()
 
-    private val app: LauncherAppState
-        get() = context.appComponent.launcherAppState
+    private val testComponent: TestComponent
+        get() = context.appComponent as TestComponent
+
+    private val bgDataModel: BgDataModel
+        get() = testComponent.getDataModel()
+
+    private val inMemoryDb: SQLiteDatabase by lazy {
+        ModelTestExtensions.createInMemoryDb(INSERTION_STATEMENT_FILE)
+    }
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_TIERED_WIDGETS_BY_DEFAULT_IN_PICKER)
-        launcherModel = mock(LauncherModel::class.java)
         mockitoSession =
             ExtendedMockito.mockitoSession()
                 .strictness(Strictness.LENIENT)
@@ -123,16 +132,34 @@
             .getAppWidgetInfo(any())
 
         `when`(launcherModel.beginLoader(any())).thenReturn(transaction)
-        `when`(launcherModel.modelDbController)
-            .thenReturn(FactitiousDbController(context, INSERTION_STATEMENT_FILE))
+
+        `when`(launcherModel.modelDbController).thenReturn(modelDbController)
+        doAnswer {}.whenever(modelDbController).loadDefaultFavoritesIfNecessary()
+        doAnswer { i ->
+                inMemoryDb.query(
+                    TABLE_NAME,
+                    i.getArgument(0),
+                    i.getArgument(1),
+                    i.getArgument(2),
+                    null,
+                    null,
+                    i.getArgument(3),
+                )
+            }
+            .whenever(modelDbController)
+            .query(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
+
+        `when`(launcherModel.modelDelegate).thenReturn(modelDelegate)
         `when`(launcherBinder.newIdleLock(any())).thenReturn(idleLock)
         `when`(idleLock.awaitLocked(1000)).thenReturn(false)
         `when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler)
+
         context.initDaggerComponent(
             DaggerLoaderTaskTest_TestComponent.builder()
                 .bindUserCache(userCache)
                 .bindIconCache(iconCache)
                 .bindLauncherModel(launcherModel)
+                .bindAllAppsList(bgAllAppsList)
         )
         context.appComponent.idp.apply {
             numRows = 5
@@ -146,20 +173,23 @@
     fun tearDown() {
         LauncherPrefs.get(context).removeSync(RESTORE_DEVICE)
         LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false))
+        inMemoryDb.close()
         context.onDestroy()
         mockitoSession.finishMocking()
     }
 
     @Test
     fun loadsDataProperly() =
-        with(BgDataModel()) {
+        with(bgDataModel) {
             val MAIN_HANDLE = Process.myUserHandle()
             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
-            LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder)
+            testComponent
+                .getLoaderTaskFactory()
+                .newLoaderTask(launcherBinder, userManagerState)
                 .runSyncOnBackgroundThread()
-            Truth.assertThat(
+            assertThat(
                     itemsIdMap
                         .filter {
                             it.container == CONTAINER_DESKTOP || it.container == CONTAINER_HOTSEAT
@@ -167,9 +197,8 @@
                         .size
                 )
                 .isAtLeast(32)
-            Truth.assertThat(itemsIdMap.filter { ModelUtils.WIDGET_FILTER.test(it) }.size)
-                .isAtLeast(7)
-            Truth.assertThat(
+            assertThat(itemsIdMap.filter { ModelUtils.WIDGET_FILTER.test(it) }.size).isAtLeast(7)
+            assertThat(
                     itemsIdMap
                         .filter {
                             it.itemType == ITEM_TYPE_FOLDER || it.itemType == ITEM_TYPE_APP_PAIR
@@ -177,12 +206,14 @@
                         .size
                 )
                 .isAtLeast(8)
-            Truth.assertThat(itemsIdMap.size()).isAtLeast(40)
+            assertThat(itemsIdMap.size()).isAtLeast(40)
         }
 
     @Test
     fun bindsLoadedDataCorrectly() {
-        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        testComponent
+            .getLoaderTaskFactory()
+            .newLoaderTask(launcherBinder, userManagerState)
             .runSyncOnBackgroundThread()
 
         verify(launcherBinder).bindWorkspace(true, false)
@@ -200,7 +231,7 @@
 
     @Test
     fun setsQuietModeFlagCorrectlyForWorkProfile() =
-        with(BgDataModel()) {
+        with(bgDataModel) {
             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
             val MAIN_HANDLE = Process.myUserHandle()
             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
@@ -208,7 +239,9 @@
             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
 
-            LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
+            testComponent
+                .getLoaderTaskFactory()
+                .newLoaderTask(launcherBinder, userManagerState)
                 .runSyncOnBackgroundThread()
 
             verify(bgAllAppsList)
@@ -221,7 +254,7 @@
 
     @Test
     fun setsQuietModeFlagCorrectlyForPrivateProfile() =
-        with(BgDataModel()) {
+        with(bgDataModel) {
             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
             val MAIN_HANDLE = Process.myUserHandle()
             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
@@ -229,7 +262,9 @@
             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 3))
 
-            LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
+            testComponent
+                .getLoaderTaskFactory()
+                .newLoaderTask(launcherBinder, userManagerState)
                 .runSyncOnBackgroundThread()
 
             verify(bgAllAppsList)
@@ -268,7 +303,9 @@
         RestoreDbTask.setPending(spyContext)
 
         // When
-        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        testComponent
+            .getLoaderTaskFactory()
+            .newLoaderTask(launcherBinder, userManagerState)
             .runSyncOnBackgroundThread()
 
         // Then
@@ -336,7 +373,9 @@
         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
 
         // When
-        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        testComponent
+            .getLoaderTaskFactory()
+            .newLoaderTask(launcherBinder, userManagerState)
             .runSyncOnBackgroundThread()
 
         // Then
@@ -375,7 +414,9 @@
         RestoreDbTask.setPending(spyContext)
 
         // When
-        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        testComponent
+            .getLoaderTaskFactory()
+            .newLoaderTask(launcherBinder, userManagerState)
             .runSyncOnBackgroundThread()
 
         // Then
@@ -414,7 +455,9 @@
         RestoreDbTask.setPending(spyContext)
 
         // When
-        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        testComponent
+            .getLoaderTaskFactory()
+            .newLoaderTask(launcherBinder, userManagerState)
             .runSyncOnBackgroundThread()
 
         // Then
@@ -444,7 +487,8 @@
             )
         val expectedAppInfo = AppInfo().apply { componentName = expectedComponent }
         // When
-        val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        val loader =
+            testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
         val actualIconRequest =
             loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests)
         // Then
@@ -474,7 +518,8 @@
             )
         val expectedAppInfo = AppInfo().apply { componentName = expectedComponent }
         // When
-        val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        val loader =
+            testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
         val actualIconRequest =
             loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests)
         // Then
@@ -505,7 +550,8 @@
         val expectedAppInfo =
             AppInfo().apply { componentName = ComponentName("differentPkg", "differentClass") }
         // When
-        val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        val loader =
+            testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
         val actualIconRequest =
             loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests)
         // Then
@@ -532,7 +578,8 @@
             )
         val expectedAppInfo = AppInfo()
         // When
-        val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+        val loader =
+            testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
         val actualIconRequest =
             loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests)
         // Then
@@ -543,6 +590,11 @@
     @LauncherAppSingleton
     @Component(modules = [AllModulesForTest::class])
     interface TestComponent : LauncherAppComponent {
+
+        fun getLoaderTaskFactory(): LoaderTaskFactory
+
+        fun getDataModel(): BgDataModel
+
         @Component.Builder
         interface Builder : LauncherAppComponent.Builder {
             @BindsInstance fun bindUserCache(userCache: UserCache): Builder
@@ -551,6 +603,8 @@
 
             @BindsInstance fun bindIconCache(iconCache: IconCache): Builder
 
+            @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder
+
             override fun build(): TestComponent
         }
     }
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
index 8db049c..fd44023 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
@@ -30,12 +30,13 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
-import com.android.launcher3.LauncherAppState
+import com.android.launcher3.InvariantDeviceProfile
 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.icons.CacheableShortcutInfo
+import com.android.launcher3.icons.IconCache
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
@@ -52,11 +53,12 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Answers
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.RETURNS_DEEP_STUBS
 import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doAnswer
@@ -71,10 +73,10 @@
     @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
     @Mock private lateinit var mockBgDataModel: BgDataModel
     @Mock private lateinit var mockContext: Context
-    @Mock private lateinit var mockAppState: LauncherAppState
+    @Mock private lateinit var mockIconCache: IconCache
     @Mock private lateinit var mockPmHelper: PackageManagerHelper
     @Mock private lateinit var mockLauncherApps: LauncherApps
-    @Mock private lateinit var mockCursor: LoaderCursor
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var mockCursor: LoaderCursor
     @Mock private lateinit var mockUserCache: UserCache
     @Mock private lateinit var mockUserManagerState: UserManagerState
     @Mock private lateinit var mockWidgetInflater: WidgetInflater
@@ -95,10 +97,9 @@
 
     @Before
     fun setup() {
+        MockitoAnnotations.initMocks(this)
+
         mUserHandle = UserHandle(0)
-        mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
-        mockWorkspaceInfo = mock<WorkspaceItemInfo>()
-        mockBgDataModel = mock<BgDataModel>()
         mComponentName = ComponentName("package", "class")
         mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
         intent =
@@ -107,52 +108,36 @@
                 `package` = "pkg"
                 putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
             }
-        mockLauncherApps =
-            mock<LauncherApps>().apply {
-                whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
-                whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
-            }
-        mockContext =
-            mock<Context>().apply {
-                whenever(packageManager).thenReturn(mock())
-                whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
-                whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
-                whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps)
-            }
-        mockAppState =
-            mock<LauncherAppState>().apply {
-                whenever(context).thenReturn(mockContext)
-                whenever(iconCache).thenReturn(mock())
-                whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
-            }
-        mockPmHelper =
-            mock<PackageManagerHelper>().apply {
-                whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
-                    .thenReturn(intent)
-            }
-        mockCursor =
-            Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
-                user = mUserHandle
-                itemType = ITEM_TYPE_APPLICATION
-                id = 1
-                restoreFlag = 1
-                serialNumber = 101
-                whenever(parseIntent()).thenReturn(intent)
-                whenever(markRestored()).doAnswer { restoreFlag = 0 }
-                whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
-                whenever(getAppShortcutInfo(any(), any(), any(), any()))
-                    .thenReturn(mockWorkspaceInfo)
-                whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
-            }
-        mockUserCache =
-            mock<UserCache>().apply {
-                val userIconInfo =
-                    mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
-                whenever(getUserInfo(any())).thenReturn(userIconInfo)
-            }
+        mockLauncherApps.apply {
+            whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+            whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
+        }
+        mockContext.apply {
+            whenever(packageManager).thenReturn(mock())
+            whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+            whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
+            whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps)
+        }
 
-        mockUserManagerState = mock<UserManagerState>()
-        mockWidgetInflater = mock<WidgetInflater>()
+        whenever(mockIconCache.getShortcutIcon(any(), any(), any())).then {}
+        whenever(mockPmHelper.getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+            .thenReturn(intent)
+        mockCursor.apply {
+            user = mUserHandle
+            itemType = ITEM_TYPE_APPLICATION
+            id = 1
+            restoreFlag = 1
+            serialNumber = 101
+            whenever(parseIntent()).thenReturn(intent)
+            whenever(markRestored()).doAnswer { restoreFlag = 0 }
+            whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
+            whenever(getAppShortcutInfo(any(), any(), any(), any())).thenReturn(mockWorkspaceInfo)
+            whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
+        }
+
+        val mockUserInfo = mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
+        whenever(mockUserCache.getUserInfo(any())).thenReturn(mockUserInfo)
+
         mKeyToPinnedShortcutsMap = mutableMapOf()
         mInstallingPkgs = hashMapOf()
         mAllDeepShortcuts = mutableListOf()
@@ -283,7 +268,7 @@
         userManagerState: UserManagerState = mockUserManagerState,
         launcherApps: LauncherApps = mockLauncherApps,
         shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
-        app: LauncherAppState = mockAppState,
+        context: Context = mockContext,
         bgDataModel: BgDataModel = mockBgDataModel,
         widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
         widgetInflater: WidgetInflater = mockWidgetInflater,
@@ -297,11 +282,11 @@
     ) =
         WorkspaceItemProcessor(
             c = cursor,
+            context = context,
             memoryLogger = memoryLogger,
             userCache = userCache,
             userManagerState = userManagerState,
             launcherApps = launcherApps,
-            app = app,
             bgDataModel = bgDataModel,
             widgetProvidersMap = widgetProvidersMap,
             widgetInflater = widgetInflater,
@@ -313,5 +298,8 @@
             shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
             installingPkgs = installingPkgs,
             allDeepShortcuts = allDeepShortcuts,
+            idp = InvariantDeviceProfile.INSTANCE.get(context),
+            iconCache = mockIconCache,
+            isSafeMode = false,
         )
 }
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 8846d65..67ee1ac 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.ui.widget;
 
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
 import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
 import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
@@ -318,7 +317,7 @@
         try {
             return MODEL_EXECUTOR.submit(() ->
                 mModel.getModelDbController().query(
-                                TABLE_NAME, null, itemIdMatch(0), null, null)).get();
+                        null, itemIdMatch(0), null, null)).get();
         } catch (Exception e) {
             throw new RuntimeException(e);
         }